这个条款可以理解成“宁可以编译器替换预处理器”。
使用常量可能比使用#define导致较小量的码,因为预处理器“盲目地将宏名称替换”可能导致目标码出现多份。
常量定义式通常放在头文件内,以便被不同的源代码含入。
对于class专属常量,为了将常量的作用域限制于类内,必须让它成为class的一个成员:而为确保此常量至多只有一份实体,必须让它成为一个static成员:
class GamePlayer {
private:
static const int NumTurns = 5; //常量声明式
int scores[NumTurns]; //使用该常量
...
}
通常 C++要求为所使用的任何东西提供一个定义式,但如果它是个class专属常量又是static且为整数类型(如ints,chars,bools),则需特殊处理。只要不取他们的地址,你可以声明并使用他们而无须提供定义式。
但如果你取某个专属常量的地址,又或者编译器坚持看见一个定义式,你就必须提供一个定义式。
const int GamePlayer::NumTurns; //定义式
请把这个式子放入实现文件而非头文件,因为class常量已在声明时获得初值,因此定义时不可以再设初值。
注意:我们无法利用#define创建一个class专属常量,因为#define并不重视作用域(scope)。一旦宏被定义,它就在其后的编译过程中有效(除非在某处#undef)。所以#define还不能提供任何封装性。
旧式编译器不允许static成员在其声明式上获得初值。“in-class”初值设定,也只允许对整数常量进行。
如果编译器不允许“static整数型class常量”完成“in-class初值设定”,可以使用“the enum hack”补偿做法。其理论基础是“一个属于枚举类型的数值可以权充ints被使用”。
class GamePlayer {
private:
enum { NumTurns = 5 };
int scores[NumTurns];
...
}
enum值得我们认识:
- enum hack 比较像 #define 而不像 const ,例如取一个 const 地址是合法的,但取一个enum 不合法。通常取 #define 的地址也不合法。
- enum是编程元模板的基础技术(见条款48)
请记住:
- 对于单纯常量,最好以const对象或enum替换#define
- 对于形似函数的宏,最好改用inline函数替换#define