编译器生成的拷贝构造函数一定会用 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 · 编译器可以隐式产生一个类的缺省构造函数,拷贝构造函数,拷贝赋值运算符和析构函数。  
2/2 首页 上一页 1 2 |