- 条款05:了解C++默默编写并调用哪些函数
- 条款06:若不想使用编译器自动生成的函数,就该明确拒绝
- 条款07:为多态基类声明virtual析构函数
- 条款08:别让异常逃离析构函数
- 条款09:绝不在构造和析构过程中调用virtual函数
- 条款10:令operator=返回一个reference to *this
- 条款11:在operator=中处理“自我赋值”
- 条款12:赋值对象时勿忘其每一个成分
条款05:了解C++默默编写并调用哪些函数
- 如果自己没声明,编译器会自动声明(编译器版本)的copy构造函数、copy assignment操作符和析构函数。如果没有声明构造函数,编译器也会声明一个default构造函数。
- 如果某个base classes将copy assignment操作符声明为private,编译器将拒绝为其derived classes生成一个copy assignment操作符。
- 如果一个类中有reference或pointer类型的数据。那么对于copy assignment操作符需要自己定义,而不是使用编译器生成版本。
条款06:若不想使用编译器自动生成的函数,就该明确拒绝
- 为了组织copying动作可以设计一个base class并且不予以实现:这行得通,甚至是member函数或friend函数——尝试拷贝HomeForSale对象,编译器便试图生成一个copy构造函数和一个copy assignment操作符,生成版会尝试调用base class的对应函数,而调用被拒绝,因为拷贝函数是private。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15class Uncopyable
{
protected:
Uncopyable() {}
~Uncopyable() {}
private:
Uncopyable(const Uncopyable&);
Uncopyable& operator=(const Uncopyable&);
};
class HomeForSale : private Uncopyable
{
// class不再声明copy构造函数或copy assignment操作符
...
};
条款07:为多态基类声明virtual析构函数
- 给base class一个virtual析构函数,此后删除derived class对象就会销毁整个对象。如果class不含virtual函数,通常表示意图不被做一个base class。
- 想实现出virtual函数,对象必须携带某些信息,主要用来在运行期决定哪一个virtual函数该被调用。它由一个vptr(virtual table pointer)指向一个由函数指针构成的数组,称为vtbl(virtual table);每个带有virtual函数的class都有一个相应的vtbl。当对象调用virtual函数时,编译器在其中寻找适当的函数指针。给base classes一个virtual析构函数这个规则只适用于polymorphic(带多态性质的)base classes身上。
条款08:别让异常逃离析构函数
- 对于析构函数中可能抛出的异常,由两种办法可以避免。一是如果抛出异常就结束程序,通常通过在析构函数调用
abort
抢先制不明确行为于死地;二是吞下它。 - 如果用户需要对某个操作函数运行期间的异常做出反应,应该提供一个普通函数来操作。然后在结束时析构函数来判断二重保险。
条款09:绝不在构造和析构过程中调用virtual函数
- 由于base class构造函数的执行更早于derived class构造函数,当base class构造函数执行时derived class的成员变量尚未初始化。如果此期间调用的virtual函数下降至derived classes阶层,那些成员变量尚未初始化,这将产生未定义行为。
- 在构造和析构期间不要调用virtual函数,因为这类调用从不下降至derived class。
条款10:令operator=返回一个reference to *this
条款11:在operator=中处理“自我赋值”
- 如果operator=函数内的*this和赋值的来源是同一个对象,潜在的delete操作可能就摧毁了全部对象。因此需要注意在复制之前要么数据最好别删除,要么通过测试是否自我赋值。
- 在operator=函数内的替换方案最好是使用所谓的copy and swap技术。
1
2
3
4
5Widget& Widget::operator=(Widget rhs)
{
swap(rhs);
return *this;
}
条款12:赋值对象时勿忘其每一个成分
- 当你编写一个copying函数,要确保复制所有local成员变量,且调用所有base calsses内的适当的copying函数。
- 对于为了消除复制代码的重复性,不该用copy assignment操作符调用copy构造函数,反之亦然。消除重复代码的做法是,建立一个新的成员函数给两者调用。这样的函数往往是private而且被命名为init。