条款05:了解C++默默编写并调用哪些函数
如果我们写了一个空类:
class Empty { };
编译器会为这个类添加一些default的函数,相当于:
class Empty { public: Empty() { ... } //default构造函数 Empty(const Empty& rhs) { ... } //copy构造函数 ~Empty() { ... } //析构函数 Empty & operator=(const Empty& rhs) { ... } //copy assigment操作符 };
其中,编译器创建的copy构造函数和copy assigment操作符只是单纯地将来源对象的每一个non-static成员变量拷贝到目标变量。编译器创建的copy assigment操作符与copy构造函数行为上基本相同,但一般只有生成的代码合法而且有适当机会证明它有意义时,编译器才会创建copy assigment操作符。例如类中有const或者引用的字段时,往往编译器会拒绝创建copy assigment操作符。
如果我们为类声明了构造函数,则编译器不再给类添加default构造函数。
条款6:若不想使用编译器自动生成的函数,就应该明确拒绝
如果不想使用default构造函数和析构函数,我们可以通过声明构造函数和析构函数来拒绝。
但是如果不想使用copy构造函数和copy assigment操作符,例如,我们不允许一下操作:
Object a1; Object a2; Object a3(a1); //不允许该操作 Object a2 = a1; //不允许该操作
如何才能拒绝上面两种情况呢?
一种方法是将copy构造函数和copy assigment操作符声明为private,这样外部就无法调用到这两个方法,编译器也不会自己添加。但是用户member函数或friend函数还是有可能调用到这两个方法,所以我们可以只声明这两个方法而不实现,如果不慎调用到,会获得一个连接错误(Link Error)。
另一种方法甚至可以将可能的连接错误提前到编译期,做法定义一个Uncopyable的基类,这个类中按上一种方法声明,而其他的想阻止对象copy的类只需要继承该基类就可以了:
class Uncopyable { protect: Uncopyable () {} ~Uncopyable () {} private: Uncopyable(const Uncopyable&); Uncopyable& operator=(const Uncopyable&); }; //其他类只需要继承Uncopyable即可 class NewClass : private Uncopyable { ... };
条款7:为多态基类声明virtual析构函数
条款8:别让异常逃出析构函数
条款9:绝不要在构造函数中调用virtual函数
条款10:令operator=返回一个reference to *this
可以实现连锁复制,如 a = b = c;
这个条款同样适用于 operator+=,-=,*=,/=等等。
条款11:在operator=中处理“自我赋值”
例如:
Widget& Widget::operator=(const Widghet& rhs) { if (this == &rhs) return *this; ... return *this; }
另外一种处理自我赋值的方法:
//copy and swap Widget& Widget::operator=(const Widghet& rhs) { Widget tem(rhs); swap(temp); return *this; }
条款12:复制对象时勿忘其每一个成分
必须确保:1.复制所有local成员变量;2.调用所有base classes内适当的copying函数。