05. 了解 C++ 默默编写并调用哪些函数
如果没有主动创建,编译器会在首次被调用时,为 class
创建默认构造函数、拷贝构造函数、拷贝赋值符( = ),以及析构函数。这些函数都是 public
且 inline
的。
除非这个 class
的 base class
自身有虚析构函数,否则编译器自动生成的是非虚析构函数。
对于 拷贝赋值符,如果 class
包含 const
成员 或者 reference
成员,以及 base class
中的拷贝赋值符为 private
时,编译器会拒绝自动生成赋值运算符。
06. 若不想使用编译器自动生成的函数,应明确拒绝
通过将相应的成员函数声明为 private
并且不进行实现,或者通过继承一个 Uncopyable
的类,可以阻止编译器自动生成。
07 为多态基类声明 virtual 析构函数
- 带有多态性质的
base classes
应该声明一个virtual
析构函数。如果函数带有任何virtual
函数,他就应该拥有virtual
析构函数。 - 如果一个
class
的设计不是用于作为base classes
使用的,就不该声明virtual
析构函数。( 存在虚函数会需要生成虚函数指针和虚函数表,占用大量空间。)
08 别让异常逃离析构函数
- 析构函数绝对不能抛出异常,如果一个析构函数调用的函数可能抛出异常,析构函数应该能捕捉任何异常,然后吞下它(不传播)或者结束程序。
- 如果客户需要对某个操作函数运行期间抛出的异常作出反应,那么class应该提供一个普通函数(而非在析构函数中)执行该操作。
09 不在构造、析构过程中调用 virtual 函数
因为父类构造、析构函数运行时,子类并不存在,故此时调用 virtual 函数不会下降至子类中。
10 令 operator= 返回一个 reference to *this
为了实现「连锁赋值」
11 在 operator= 中处理 「自我赋值」
确保任何函数操作一个以上对象,而其中多个对象为同一对象时,行为仍然正确。
12 复制对象时勿忘其每一个成分
- Copy 函数应该确保复制「对象内的所有成员遍历」 以及「所有 base class 成员」。
- 不要尝试以某一个 coping 函数实现另一个 coping 函数。应该把相同的代码部分放在第三个函数中,并由两个 coping 函数共同调用。