类名(){... 类名(const 类名& rhs){...} ~类名(){...} 类名& operator=(const 类名& rhs){...}
### 06:若不想使用编译器自动生产的函数,就该明确拒绝
为了阻止编译器自动生产函数:自行声明函数
为了防止别人调用:声明为private
为了防止友元函数和成员函数调用:只定义不实现
**为驳回编译器自动提供的机能,可将相应的成员函数声明为private并且不予实现**
### 07:为多态基类声明virtual析构函数
* 带有多态性质的基类应该声明一个virtual析构函数。如果类带有任何virtual函数,它就更应该拥有一个virtual析构函数。
* 类的设计目的如果不是作为基类使用,或不是为了具备多态性,就不该声明virtula析构函数。
### 08:别让异常逃离析构函数
原因:析构函数吐出异常,会使程序过早结束或出现不明确的行为。比如:销毁十个成员对象,在销毁第一个的时候出现异常,这会使后面的成员对象没有被销毁就退出程序了。
* 析构函数绝对不能吐出异常。如果一个被析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常,然后吞下它们或结束程序。
* 如果需要对某个操作函数运行期间抛出的异常做出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。
### 09:绝不在构造和析构过程中调用virtual函数
当基类在构造函数调用纯虚函数,在创建派生类对象时,会先调用基类的构造函数,由于基类构造函数调用了纯虚函数,同时又因**基类构造期间virtual函数不会下降到派生类阶层(基类构造期间,virtual不是virtual)**,基类函数没有实现,进而导致派生类对象无法创建。(可能回报错:找不到函数的实现代码)。
* 在构造和析构期间不要调用virtual函数,因为这类调用从不下降至派生类
### 10:令operator=返回一个reference to \*this
... 类名& operator=(const 类名& rhs) { ... return *this; }
* 这个协议适用于所有赋值相关运算
* 这仅仅是个协议,并无强制性,你可以不遵循它。然而这个协议被所有内置类型和STL提供的类型共同遵循。
* 令赋值操作符返回一个reference to \*this
### 11 在operator=中处理自我赋值
例子:pa和pb是指向同一个对象的指针,有如下语句:
pa = pb; //赋值函数 operator =(const xxx& rhs) { delete m_p; m_p = new XXX(*rhs.m_p) return *this; }
operator=中一般会先删除自己的成员对象(如果有),使用传入的对象(别名)创建一个相同的对象,赋给该类的成员对象变量,然后返回*this。**发现自己持有一个指针指向一个已被删除的对象**。
解决方法:
1.证同测试-判断是否是自我赋值,如果是直接返回*this
缺陷:如果创建成员对象中new异常,之前的成员也被删除了,又没创建成功,这样的指针有问题。
2.先创建对象,再删除
缺陷:自我赋值的效率问题,如果将证同测试加进来,会增加新的控制分支,代码也会变长,也会降低执行速度。
3.copy and swap-先复制副本,再将this和副本交换。
* 确保当对象自我赋值时operator=有良好行为,技术包括以上三种
* 确保任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。
### 12:复制对象勿忘其每一个成分
当基类中添成员对象时,必须同时修改拷贝函数(拷贝函数和拷贝赋值函数),发生继承,一定在派生类拷贝构造函数后加上:baseClass(rhs)调用父类的构造函数;拷贝赋值函数体里加上baseClass::operator=(rhs)。