5.1 对于独立的一个空类,C++编译器会帮你自动生成:默认构造函数、拷贝构造函数、析构函数(non-virtual)和赋值操作符函数(operator=),如果这些函数在代码里被需要。
5.2 如果这个类有声明有实参的构造函数,那么编译器不会添加默认构造函数。
如果这个类有基类,且基类析构函数是virtual的,这时它的析构函数才是virtual的。
5.3 编译器拒绝生成operator=函数的情况:一是有引用成员变量,二是有const成员变量,三是基类的operator=函数是私有的。
编译器自动生成的函数都是public的,如果想阻止编译器自动生成,可以:
6.1 将相应的函数声明为private(成员函数和友元函数仍可调用),并且不提供实现。
6.2 如阻止对象copy,可提供基类如Uncopyable,这个类不含任何成员变量,拷贝构造和operator=函数声明为私有且无实现。子类私有继承Uncopyable。
7.1 带多态性质的基类,应该声明一个virtual析构函数。
任何class只要带有virtual函数,都应该有一个virtual析构函数。
7.2 如果class设计的目的不是作为基类使用,或不是为了具备多态性,就不应该声明virtual析构函数。因为带虚函数的类,会自动多一个虚函数表指针,需要更多空间且不具有可移植性。
7.3 析构函数的调用顺序:最深层派生类的析构先调用,然后再逐层调基类的析构函数。
8.1 C++不禁止析构函数抛出异常,但它不鼓励这样做。因为如果在析构期间有两个或两个以上的异常发生,程序若不是结束执行就是导致不明确行为。
8.2 析构函数不要抛出异常。如果程序在”析构期间发生错误“后无法继续执行,强迫结束程序是个合理选项。另一方案是吞掉(不传播)异常,即catch到异常后只是记录,不做其它动作。
8.3 如果析构函数调用的函数可能抛出异常,析构函数应该捕捉任何异常。
8.3 如果客户需要对某个操作函数运行期间抛出的异常做处理,那么类应该一个普通函数(非析构函数中)执行该操作。
在构造和析构期间不要调用virtual函数,因为这类调用从不下降至继承类(没有多态)。
9.1 构造函数的调用顺序是,先调基类构造,再调继承类构造。在基类构造函数中调用虚函数,此时继承类尚未构造,其成员变量也没有初始化,所以此时对象还是基类对象,基类构造函数里调用的其它函数,只能是基类定义的函数。
9.2 同样,一旦继承类析构函数开始执行,对象内的继承类的成员变量就是未定义值。当进入基类的析构函数后对象就成为一个基类对象。 基类析构函数里调用的其它函数,只能是基类定义的函数。
这样做的目的是方便链式赋值。这个协议也适用于其它赋值运算符,如+=、-=、*=。
11.1 确保当对象自我赋值时operator=有良好的行为。其中包括比较"来源对象"和"目标对象"的地址、精心周到的语句顺序(特别有delete,new操作时)、以及copy-and-swap。
11.2 确定任何函数如果操作一个以上的对象,而其中多个对象是同一个对象时,其行为仍然正确。
12.1 Copying函数(拷贝构造、赋值操作)应该确保复制"对象内的所有成员变量",及"所有基类成分(成员)"。
12.2 不要尝试以某个copying函数调用另一个copying函数来消除重复代码,应该将共同部分放进第三个函数中,并由两个copying函数共同调用。这第三个函数通常叫init,且是private的。