条款01:视C++为一个语言联邦
C++的四个次语言
①C
②Object-OrientedC++
③Template C++
④STL
C++是个多重范型编程语言,同时支持过程形式、面向对象形式、函数形式、泛型形式、元编程形式的语言。C++高效编程守则视状况而变化,取决于使用C++的哪一部分
条款02:尽量以const、enum、inline替换#define
不带参数的宏:用const和enum代替
宏定义#define:预编译期→不进入符号表,只是简单的替换
const、enum定义的常量:编译期→进入符号表,支持类型检查和访问限制
关于访问限制,#define并不重视作用域。一旦宏被定义,它就在其后的编译过程中有效,所以#define不仅不能够用来定义class专属常量,也不能够提供任何封装性。
带参数的宏:用inline代替
宏看起来像函数,但会有很多缺点,比如下面这个程序:
#include<iostream>
#define square(a) a*a
using namespace std;
int main()
{
cout << square(2+1) << endl;
return 0;
}
在宏中,实现的是平方的功能,计算出的结果可能会是square(3),结果是9。但是事实上的结果是5,原因很简单,宏只是简单的替换,所以替换的结果就是
2 +1 * 2 + 1
根据优先级,计算出来的结果自然是5。
这样的情况并不是简单的加上括号就行的,因为还会有比括号更高的优先级的算符影响运算结果,比如:
#include<iostream>
#define square(a) a*a
using namespace std;
int main()
{
int i = 2;
cout << square(++i) << endl;
return 0;
}
替换的结果就是( ++i ) * (++i ),i自增了两次,所以结果是4*4,而不是3*3。
要解决这个问题,最好的方法就是不用宏定义,而是用函数。但是函数又存在一个问题,就是调用的时候会有保存现场和回复现场(压栈弹栈),会影响效率。如果我们在前面加上关键字“inline”,就会告诉编译器:把这段函数体部分直接替换到调用处,而不是用栈机制调用函数。
条款03:尽可能使用const
const就是告诉编译器该指定的对象应保持不变。如果尝试修改const的变量,编译器会报错。同时也告诉我们,const对象是在声明时就要初始化。
修饰指针
说到指针,往往会涉及到两个变量:指针本身和指针指向的变量。所以const应用于指针也有多重含义:const int* p = &x; //指针本身是变量,指向的是常量
*p = 3; //试图修改指针指向的对象,但x已经是常量,错误
p = &y; //试图修改指向,指向其他对象,可以
int* const p = &x; //指针本身是常量,指向的是变量
*p = 3; //试图修改指针指向的对象,将x改为3,可以
p = &y; //试图修改指向,但指向已经是常量,错误
const int* const p = &x; //指针本身和指向的都是常量,都不可修改
总结:关键字const出现在星号左边,表示指向的对象是常量。如果出现在右边,表示指针自身是常量。如果出现在两边,则指向对象和指针两者都是常量。
修饰成员函数
const放在类中的成员函数后面,表示这个成员函数不会修改类的成员变量。