这是篇读书笔记,只记录自己的理解和总结,一般情况不对其举例子具体说明,因为那正是书本身做的事情,我的笔记作为梳理和复习之用,划重点。我推荐学C++的人都好好读一遍Effective C++ 系列,真是好书啊,对于学完C++ 基础知识的人,这是本高阶秘籍。值得注意的是 More Effective C++ 是以1997年的C++标准写的,那时候标准还不完善,20多年过去了,很多语言的漏洞和技术可能被新特性取代了,应该注意最终向新标准看齐。
笔记
-
条款1:仔细区别pointers 和 reference。 reference 必然指向某个对象,不可以为 null , 不可以改变指向;指着可以为空,可以改变指向。 重载操作符 operator[] 的时候返回reference 更好。
int &a =0;\\错误!
, 而int *a = 0 ;\\合法
- 条款2: 最好使用C++ 转型操作符。从可读性和规范来说,不应该使用C语言的转型了,而应该使用以下四种转型操作符。
static_cast<T>() | const_cast<T>() | dynamic_cast<T>() | reinterpret_cast<T>() | |
---|---|---|---|---|
操作 | 普通转型操作 | 去除某个对象的常量性 | 继承体系中安全的向下转型或者跨系转型 | 用来转换函数指针的类型 |
注意事项 | 与C语言旧式转型有相同威力与意义 | 只能用于继承体系中 | 不具备移植性 |
dynamic_cast 可以把指向基类的指针或者引用转换为指向派生类的指针或者引用
-
条款3:绝对不要以多态的方式处理数组。 所以如果用基类的数组存派生类对象,因为基类对象占用的内存和派生类对象占用内存大小不一样会导致寻址出错。结果不可预期。析构也会出错,通过base class 的指针删除derived classes 的对象构成的数组,结果未定义。多态和指针算术不能混用。
array[i] 表示的是 *(array+i);
条款4:非必要不提供 default constructor。 提供了默认构造函数就是表明构造这个对象不需要额外的参数,表明成员参数都可能被初始化或者类的设计者有责任检查成员函数是否初始化,带来额外的负担。 如果不提供默认构造函数,则在使用对象数组的时候需要逐个构造,这里还介绍了一种分配raw memory 和placement new 的技术(可以参见条款8)避免过度使用内存; 此外,如果不提供默认构造函数,则不适用许多模板容器类 tamplate-based container class; 还有就是对于虚基类,如果没有默认构造函数则要求派生类的使用者了解构造参数的意义。最终实践是如果提供默认你构造函数,请记得保证成员有意义。
有个三五法则专门讲关于构造、析构函数的,准备写一篇总结,专门讲述这方面的。
总结
- 区分 reference 引用和pointer 指针;
- 最好使用 C++ 的转型操作符,弃用旧的C 转型方式;
- 多态和指针运算不能混用(数组索引用了指针算术);
- 除非必要,否则不提供默认构造函数。