条款2 尽量以const,enum,inline 替换#define
这个条款可以理解为“以编译器替换预处理器”
由于预处理器(如#define等)并不被视为语言的一部分,所以让你
#define ASPECT_RATIO 1.653
这样定义时,标记名称ASPECT_RATIO或许从未被编译器看见,所以如果这样运行时出错,编译错误信息往往会提到1.653,如果标记名称ASPECT_RATIO在一个并非你写的头文件里,就会为了追踪它在哪里而浪费时间。
原因:你所使用的名称可能并未进入记号表(symbol table)
解决方法:用一个常量替换上述的宏#define:
const double AspectRatio=1.652;//大写名称通常用于宏,这里改变写法
语言常量AspectRatio一定会被编译器看到,因此会进入记号表
此外:对于浮点常量(就如上例),使用常量可能比使用#define导致较小量的码。因为预处理器“盲目的将宏名称ASPECT_RATIO替换为1.653”可能导致目标码内出现多份1.653
以常量替换#define时,两种特殊情况
一:定义常量指针:
由于常量定义式通常被放在头文件(方便被不同的源码含入),所以要把指针(并不是指针所指之物)声明为const。
例如:如果要在头文件定义一个常量(不变的)char*-based字符串,必须写const两次
const char* const authorName="Scott Meyers";
但是通常string对象比其前辈char*-based更合适。所以往往可以这样定义
const std::string authorName("Scott Meyers");
二:class专属常量。
为了将常量的作用域(scope)限制于class内,必须让它成为class的一个成员(member);而为了确保此常量最多有一份,必须让它成为一个static成员:
class GamePlayer{
private:
static const int NumTurns=5;//常量声明式
int scores[NumTurns]; //使用该常量
...
};
这里的NumTurns是声明式,而非定义式。
通常C++要求你对使用的任何东西提供一个定义式。但如果它是个class专属常量又是static且为整数类型(intergral type;例如ints,chars,bools),就需要特殊处理。只要不取它们的地址。就可以声明并使用而无需提供定义式。
如果你要取其地址或者编译器(不正确的)坚持要看到定义式,就必须提供一下定义:
const int GamePlayer::NumTurns;//记得吧式子放入头文件而不是实现文件
由于在声明时获得初值,因此定义时不可以再设初值
PS:无法用#define创建一个class专属常量,因为#define并不重视作用域。一旦宏被定义,它在其后的编译过程中有效(除非被#undef).
所以#define不能定义class专属常量,也不能提供封装性。
旧编译器也许不支持static成员在声明式上获得初值。此外“in-class初值设定”也只允许对整数常量进行。那就把初值放在定义式。
但如果class编译期间需要 一个class常量值,如上述的Gameplayer::score即编译器坚持要在编译期间知道数组大小。那么可以改用”the enum hack“补偿做法。
the enum hack补偿做法:理论基础:一个属于枚举类型的数值可权充ints被使用。
例如:
class Gameplayer{
private:
enum{NumTurns=5};//"the enum hack"令NumTurns成为5的一个记号名称
int scores[NumTurns];//ok
}
从这里来看enum hack在行为方面类似于#define而不是const。
enum可以帮助你阻止别人获得一个pointer或reference指向你的某个整数常量
define误用,以它实现宏,宏看起来像函数,但不会招致函数调用带来额外开销。
错误示范:宏夹带宏实参,调用函数f
#define CALL_WITH_MAX(a,b) f((a)>(b)?(a):(b))
int a=5,b=0;
CALL_WITH_MAX(++a,b);//a被累加2次
CALL_WITH_MAX(++a,b+10);//a被累加1次
出错,调用f之前,a的递增次数竟然取决于它被拿来和谁作比较
建议改为
template<typename T>
inline void callWithMax(const T& a,const T&b){
f(a>b?a:b);
}
callWithMAX是一个真正的函数,他遵守作用域和访问规则
- 对于单纯常量,最好用const对象或者enums替换#define
- 对于形似函数的宏,最好改用inline函数替换#defines
本文来自博客园,作者:{BailanZ},转载请注明原文链接:https://www.cnblogs.com/BailanZ/p/16086880.html