东阳的学习笔记
条款5:了解C++默默编写并调用哪些函数
- C++默认合成一个空构造函数,copy构造和copy运算符(有条件的)
- 若成员变量为引用类型,C++的响应是拒绝编译
- 若class包含引用/const类型,则需要自定义copy操作
- 当成员变量为指针类型时,最好也自定义copy操作
记住:
编译器可以暗自为class创建default构造函数、copy构造函数、copy赋值、析构函数。但是,往往无法满足需求
条款6:若不想使用编译器自动生成的函数,就该明确拒绝
- 在某些特殊场景中,可能并不允许copy操作,此时应该明确拒绝
- 可将其一一定义为private并且不加实现,这样就可以拒绝编译器的合成请求
条款7:为多态基类声明virtual析构函数
- 若未将base类析构函数定义为virtual,则可能产生局部销毁问题
- 任何class只要带有virtual函数都几乎也应该有一个虚析构函数
- 含有虚函数会增大对象体积
- 不要试图继承一个标准容器或者任何一个带有 non-virtual 析构函数的类
记住:
- 带有多态性质的 base class都应该声明一个 virtual 析构函数
- 如果class带有任何virtual函数,它应该有一个虚析构函数
- Classes如果不是作为base class使用,或者不是为了具备多态性,则不应该声明virtual析构函数
条款8:别让异常逃离析构函数
- C++中析构函数不应该抛出异常
- 析构函数绝对不要抛出异常!!!(比如在析构函数内调用其他函数时,需要对异常进行捕获,并处理)
条款9:绝对不要在构造和析构函数中调用虚函数
- 在构造阶段虚函数不再是虚函数!!!
- 一旦析构函数开始执行,所有的derived class 成员变量便呈现未定义值
- 纯虚函数有助于发现错误
- 避免代码重复的一个好的做法是将相同的部分放进一个 non virtual 的 init 函数中
- 另一个好的方法是使用带额外参数的 non-virtual
条款10:令operator = 返回一个 *this 的引用
为了实现连续赋值
条款11:在operator = 中处理 “自我赋值”
- 不要忽视自我赋值的发生
- 当成员对象含有指针/引用时,自我赋值可能会引起空悬指针的发生
- 传统的做法是,加一个判等语句,但是记住 80-20, 这显然不是一个好方法(发生频率低)
- 在处理自我赋值时更倾向于不予理会。
- swap函数是一个好办法
记住:
- 请确保 operator= 有良好行为。其中技术包括比较 “来源对象” 和 “目标对象” 的地址、精心周到的语句顺序、以及 copy-and-swap。
- 确保任何函数如果操作一个以上的对象,而其中多个对象是同一对象时,其行为依然正确。
条款12:复制对象时勿忘其每一个成分
- 如果你为 class 添加了成员对象,你必须同时修改copying函数;如果是派生类,还需要同时考虑其基类成员
- 为派生类撰写copying函数时,必须很小心地复制其 base class 部分。那些成员往往是 private ,所以无法直接访问,而应该让 derived class 的 copying 函数调用相应的 base class 函数。
- 正确的做法是:i 复制所有的 local 成员变量 ii 调用 base class 内适当的 copy 函数。
记住:
- Copying 函数应该确保复制 “对像内所有的成员变量” 及 “所有的 base class 成分”
- 不要尝试用 copying构造 copying 赋值相互实现, 如有重复代码, 应将相同的机能放入第三个函数当中去。