您可以自由地共享和演绎本文稿, 只需遵守开源协议[CC By 4.0]
如果这篇文章帮助到你, 可以请我喝一杯咖啡~
这是Effective C++的学习记录。
条款01:视C++为一个语言联邦
C++语言规范集成了大量的编程理念,这就导致了C++编程没有固定的范式,它可以是过程的、面向对象的、模块化的、泛型的或者元编程形式的,它的应用灵活性非常高,编写一个C++项目主要来讲存在这四个角度:
- 过程主导的C语言式编程:C++的底层实现大部分依赖于C,我们就可以用C++来写C
- 面向对象:是C with Classes的理念,包括数据封装原则等的一系列面向对象编程规范被引入
- 泛型:比较小众的次语言
- STL:拥有固定接口定义的程序库
根据需要实现的功能不同,我们的编程核心思维理念可能会在上述四个中不断切换,你甚至可以在同一份文件中体现不同的编程方略。
故不可以将C++认为是一个具有唯一守则的语言,理解这一点是写好C++的基础。
条款02:以const, enum, inline替换#define
C++的宏在编译时是由预处理器预先处理的,如果使用如下的写法,
#define pi 3.14
....
S = r * r * pi;
编译器的其他部分看到的语句将是
S = r * r * 3.14
对应的非终结符号将是id** = **id** * **id** * **num,而num类型的token是不会进入记号表的,这就会导致几个问题
- 如果发生编译错误,由于编译器的较后部分无法看到宏变量的名称
pi
,编译器返回的信息是字面的数值,如3.14
。如果是3.14还好,但如果这个宏的值是一个其它的数,而这个宏所在的头文件又刚好是其他人写的呢? - 由于编译器认为宏变量是一个数字型词法单元,故词法分析器不会将它加入符号表中,这就会导致我们编译的中间码中出现大量的数字字面量,这减慢了编译速度和编译器后端优化效率
- 同时
#define
不重视作用域,这可能不利于数据封装
同时,使用宏来实现简单的函数会出现更严重的问题:如
#define max(a, b) (a) > (b) ? (a) : (b) //务必记得小括号
....
int a = 15;
max(++a, 10); // 此时a被累加2次
max(++a, 20); // 此时a被累加1次
我们发现,由于宏的实现是直接使用宏表达式替换原表达式,没有传参压栈的过程,自增运算就可能出现问题(较大的表达式会在?
后的语句中被多调用一次)。这个max实现无法得到稳定的结果,所以我们只能使用inline
函数。