[C++]Effective C++笔记
文章目录
导读
|
|
copy 构造 与 copy赋值的区别:
- 如果一个新对象被定义(如w3),一定会有个构造函数被调用,不可能调用赋值操作。
- 如果没有新对象被定义(如前述 w1 = w2),就不会有构造函数被调用,那么就是赋值操作被调用。
01.视C++为一个语言联邦
今天的C++是个 多重范型编程语言,同时 支持过程形式、面向对象形式、函数形式、泛型形式、元编程形式的语言。
将C++视为一个由相关语言组成的联邦; 四种主要的次语言:
- C;C++是以C为基础的。区块,语句,预处理器,内置数据类型,数组,指针都来自于C。当以C++内的C成分工作时,高效编程守则映照出C语言的局限性:没有模板,没有异常,没有重载……
- Object-Oriented C++;C with Classes所诉求的部分:classes(包括构造函数和析构函数)、封装(encapsulation)、继承(inheritance)、多态(polymorphism)、virtual函数(动态绑定)等等
- Template C++;C++的泛型编程部分。由于templates带来的崭新的编程范型 即 template metaprogramming(TMP,模板元编程)
- STL。
注意:C++高效编程守则视状况而变化,取决于你使用C++的哪一部分。
02.尽量以const,enum,inline替换#define
|
|
enum hack的行为某方面说比较像 #define 而不像const。
例如:取一个const的地址是合法的,但取一个enum的地址就不合法,而取一个#define的地址通常也不合法。
”enum hack“是template metaprogramming的基础技术(条款48)
- 对于单纯常量,最好以const对象或enums替换#defines.
- 对于形似函数的宏(macros),最好改用inline函数替换#define。
03.尽可能使用const
const
- 如果const 出现在 * 左边,表示被指物是常量,此const为 底层const;
- 如果const 出现在 * 右边,表示指针自身是常量,此const为 顶层const。
- 如果出现在 * 两边,表示被指物和指针两者都是常量。
const成员函数
将const实施于成员函数的目的,是为了确认该成员函数可作用于const对象身上。
- 使得class接口比较容易被理解。得知哪个函数可以改动对象内容而 哪个对象不行,这很重要。
- 使”操作const对象“成为可能,这对编写高效代码很关键。
两个成员函数如果只是 常量性(constness)不同,可以被重载,如下代码所示:
|
|
const 成员函数不可以更改对象内任何non-static成员变量。
在const 和 non-const成员函数中避免重复 (在non-const成员函数中调用const成员函数)
|
|
- 声明为const可帮助编译器侦测出错误用法。const可被施加于任何作用域内的对象、函数参数、函数返回类型、成员函数本体;
- 当const 和 non-const成员函数有实质等价的实现时,令non-const版本调用const版本可避免代码重复。
04.确定对象被使用前已经先被初始化
使用成员初始化列表的效率 比 基于赋值的版本的构造函数效率更高。因为后者需要先调用 默认构造函数为成员变量设初值然后对它们赋予新值。
成员初始化列表的初始化顺序是按照 成员变量声明的顺序 进行初始化的,而不是初始化列表给定的顺序。
C++有着固定的 ”成员初始化次序“。 base classes更早于其derived classes被初始化,而class的成员变量总是 以其声明次序被初始化。
多个编译单元内的non-local static对象经由”模板隐式具现化(implicit template instantiations)“形成(而后者自己可能也经由”模板隐式具现化“形成),不但不可能决定正确的初始化次序,甚至往往不值得寻找”可决定正确次序“的特殊情况。
解决方法:将每个non-local static对象搬到自己的专属函数内(该对象在此函数内被声明为static)。这些函数返回一个reference指向它所含的对象。然后用户调用这些函数,而不直接指涉这些对象。(即 non-local 对象被local static对象替换了,这是Singleton模式的一个常见实现手法)
05.了解C++默默编写并调用哪些函数
空类,如果自己没声明函数,编译器就会为它声明(编译器版本的)一个拷贝构造函数,一个拷贝赋值操作符和一个析构函数;如果没声明任何构造函数,编译器会声明一个默认构造函数。所有这些函数是public且inline的。
编译器产出的析构函数是 non-virtual,除非这个class的base class自身声明有virtual 析构函数。
07.为多态基类声明virtual析构函数
给base class一个virtual析构函数(此规则只适用于带有多态性之的base class上),此后删除derived class对象就会销毁整个对象,包括所有derived class成分。(否则可能出现只消毁了base class成分,而没有销毁derived class成分 这样的一个”局部销毁“现象。)
如果class不含virtual函数,通常表示它并不意图被用作一个base class。任何class只要带有virtual函数都几乎确定应该有一个virtual析构函数。
- 带多态性质的base classes应该声明一个virtual析构函数,如果class带有任何virtual函数,它就应该拥有一个virtual析构函数;
- Classes的设计目的如果不是作为base classes使用,或不是为了具备多态性,就不该声明为virtual函数。如 标准string和STL容器都不被设计作为base classes使用。
文章作者 fzhiy
上次更新 2022-04-13