总结Effective C++条款

最近重读了《Effective C++》,对一些复杂的知识点会专门写文章分析,这里将一些小的知识点总结一下,但不会涵盖书里的所有内容。

条款2

  • 良好的用户自定义类型的特征是它尽量能与内置类型兼容

  • 宁可用编译器替换预处理器

  • 尽量多用const,而不是宏定义.宏属于模块化的设计概念,会破坏封装性

  • 常量可能比#define产生较小量的代码.

  • 如果类需要用到多个常量,不要用const数组,而是改用枚举

  • 对于宏形式的函数,最好用内联函数取代

条款3

  • 希望迭代器指向的东西不可改动,需要const_iterator

条款4

  • 永远在使用对象前初始化.对于int x;,有些编译器会将x初始化为0,有些却不会,所以无论之后有没有用到x,都要先对其初始化,比如int x=0;

  • 成员变量如果是const或引用,它们只能用成员列表初始化的方法进行初始化

条款5

  • 编译器自动生成的析构函数不是virtual,除非这个类的基类的析构函数是virtural

  • 编译器自动生成的4个函数都是public

  • 如果基类的copy构造函数和copy运算符是private,编译器不会为派生类生成它们

  • 派生类的copy构造函数可以尽量不定义

条款6

  • 定义uncopyable类是很好的禁止使用copy构造函数和copy运算符的方法,它的析构函数可以不是virtual,派生类不必以public继承它,也没有成员变量,也可以用于多重继承

  • 类的不可拷贝特性是可以继承的,例如凡是继承自uncopyable的类都不能使用copy构造函数和赋值运算符

条款7

  • 如果基类析构函数不声明为virtual,析构时不会调用派生类的析构,可查看原因分析

  • 如果一个类不做基类,就不要有virtual析构函数或其他虚函数,因为虚指针会增大类的体积。 反过来,只要一个类做基类,就要有virtual函数

  • 当类至少有一个虚函数时,为它声明virtual析构函数,否则编译器有报警

  • 对于抽象类,可以将析构函数声明为pure virtual析构函数

条款8

  • 析构函数里不要抛出异常,否则会导致不确定行为

条款9

  • 构造函数和析构函数中都不要调用virtual函数,因为基类构造时,virtual函数不会下降到派生类阶层,或者说此时的virtual函数还不是virtual函数

  • 对于存在多个构造函数的情况,为避免代码重复,要把同样的代码放到一个函数里,比如init

条款10

  • 赋值运算符(包括+= -= *=)的返回最好是return *this,这符合STL等标准库的风格

条款12

  • 自定义copy构造函数或运算符时,需要复制所有的成员变量,如果少复制了,编译器不会报警或报错

  • 派生类的copy构造函数或运算符,无法像平时那样对基类的private成员变量赋值,因为无法访问private的变量,只能显式调用基类的operator =, 比如: Base::operator=(obj);

条款15

  • 多使用智能指针shared_ptr,它可以返回原始指针,显式方法是get()函数,隐式方法是取指针操作符->

条款16

  • new和delete必须配对,[]必须都有或都没有。千万避免new没有[],delete有[],这会导致程序不停运行析构函数

条款18

  • 有时的形参可以用wrapper类型,而不是内置类型

  • 保证接口的一致,比如STL容器都有个size的成员函数

  • 可以让一些返回指针的函数返回智能指针,比如工厂函数

条款21

  • 函数内返回对象时,不要返回其引用。因为引用指向局部变量,而局部变量在函数退出前销毁,所以会出现无定义行为。

条款22

  • 成员变量应该都是private,将它们隐藏在函数接口的背后,如果放到public,直接使用成员变量会降低封装性。如果破坏了成员变量,会破坏太多的客户码

  • 成员变量的封装性和成员变量的内容改变时破坏的代码量成反比

  • protected变量被消灭时,所有用到它的派生类的代码都要破坏,所以封装性也很差

条款24

  • 若函数参数都要进行类型转换,应该使用非成员函数

  • 成员函数的反面是非成员函数,不是friend函数,friend应该尽量避免

条款26

  • 如果某个类的对象没有用到,就不应该声明,否则运行构造和析构函数都会耗费成本

  • 对象初始化用构造函数比=运算符的效率高

  • 对变量定义后应马上初始化,然后马上使用,中间不要隔太远

  • 变量定义在循环内比外面更好,后者造成作用域更大,对程序维护性不好

条款27

  • 代码中尽量避免dynamic_cast,它会降低效率

  • 避免连续的cast转型,尤其是dynamic_cast

条款32

  • public继承是一种is-a的关系,每一个派生类的对象也是基类的对象

  • 程序的错误最好能在编译期检测出来,而不是运行期

条款34

  • public继承涉及到函数接口继承和实现的继承

  • 纯虚函数实际上是可以提供定义的,这个用法比较罕见,知道即可

  • 虚函数使派生类继承了其缺省实现,但这可能造成危险

条款36

  • 不要重新定义继承而来的non-virtual函数,虽然没有错误,但违反了is-a原则,这种情况下干脆不要使用public继承