AutoCAD 3DMAX C语言 Pro/E UG JAVA编程 PHP编程 Maya动画 Matlab应用 Android
Photoshop Word Excel flash VB编程 VC编程 Coreldraw SolidWorks A Designer Unity3D
 首页 > C++

C++箴言:了解C++偷偷加上和调用了什么

51自学网 http://www.wanshiok.com

 

  编译器生成的拷贝构造函数一定会用 no1.nameValue 和 no1.objectValue 分别初始化 no2.nameValue 和 no2.objectValue。nameValue 的类型是 string,标准 string 类型有一个拷贝构造函数,所以将以 no1.nameValue 作为参数调用 string 的拷贝构造函数初始化 no2.nameValue。而另一方面,NamedObject<int>::objectValue 的类型是 int(因为在这个模板的实例化中 T 是 int),而 int 是内建类型,所以 no2.objectValue 将通过拷贝no1.objectValue 的每一个位来初始化。

  编译器为 NamedObject<int> 生成的拷贝赋值运算符本质上也会有同样的行为,但是,通常情况下,只有在结果代码合法而且有一个合理的可理解的逻辑时,编译器生成的拷贝赋值运算符才会有我所描述的行为方式。如果这两项检测中的任一项失败了,编译器将拒绝为你的类生成一个 operator=。

  例如,假设 NamedObject 如下定义,nameValue 是一个 string 的引用,而 objectValue 是一个 const T:

template<class T>

class NamedObject {
 public:
  // this ctor no longer takes a const name, because nameValue
  // is now a reference-to-non-const string. The char* constructor
  // is gone, because we must have a string to refer to.

  NamedObject(std::string& name, const T& value);
  ... // as above, assume no
  // operator= is declared
 private:
  std::string& nameValue; // this is now a reference
  const T objectValue; // this is now const
};

  现在,考虑这里会发生什么:

std::string newDog("Persephone");
std::string oldDog("Satch");

NamedObject<int> p(newDog, 2); // when I originally wrote this, our
// dog Persephone was about to
// have her second birthday
NamedObject<int> s(oldDog, 36); // the family dog Satch (from my
// childhood) would be 36 if she
// were still alive

p = s; // what should happen to
// the data members in p?

  赋值之前,p.nameValue 和 s.nameValue 都引向 string 对象,但并非同一个。那个赋值对 p.nameValue 产生了什么影响呢?赋值之后,p.nameValue 所引向的字符串是否就是 s.nameValue 所引向的那一个呢,也就是说,引用本身被改变了?如果是这样,就违反了常规,因为 C++ 并没有提供使一个引用引向另一个对象的方法。换一种思路,是不是 p.nameValue 所引向的那个 string 对象被改变了,从而保持指针或引用还是指向那个对象,也就是说,赋值并没有直接影响对象?这是编译器产生的拷贝赋值运算符应该做的事情吗?

  面对这个难题,C++ 拒绝编译器产生代码。如果你希望一个包含引用成员的类支持赋值,你必须自己定义拷贝赋值运算符。面对含有 const 成员的类时,编译器也会如此行事(就象上面那个改变后的类中的 objectValue)。改变 const 成员是不合法的,所以编译器隐式产生的赋值函数无法确定该如何对待它们。最后,如果基类将拷贝赋值运算符声明为 private,编译器拒绝为其派生类产生隐式的拷贝赋值运算符。毕竟,编译器为派生类产生的拷贝赋值运算符也要处理其基类部分,但如果这样做,它们当然无法调用那些派生类无权调用的成员函数。

  Things to Remember

  · 编译器可以隐式产生一个类的缺省构造函数,拷贝构造函数,拷贝赋值运算符和析构函数。

 
 

上一篇:C++箴言:拒绝不想用的编译器产生的函数  下一篇:C++箴言:视类设计为类型设计