中“宁可以编译器替换预处理”算是另一种提法,不过这个应该是概括性的说法吧
主要事项注意如下:
1用const double AspectRatio=1.653;代替#define ASPECT_RATIO 1.653
原因是预编译时define会被简单的替换,这样在编译时丢掉了ASPECT_RATIO,如果不正
当使用了ASPECT_RATIO编译时提示出错的可能只是1.653,这时候查找起来麻烦多了
另一个原因是定义成变量后编译时只有一份拷贝,节约了代码
当然这个条款也有特例
1)当出现指针的时候要这样
const char * const autherName = "Scott Mayers" ; |
即指针和其内容都不可变,当然如果是字符串string会比上面的char更合适
const std::string autherName("Scott Mayers");
2)注意class的专属常量,通过使得常量成为class的一个member将常量作用域限制在class内,而#defnie做不到。
通过使用static使常量只有一份拷贝
class GamePlayer(){ |
|
private : |
|
static const int NumTurns = 5; |
|
int scores[NumerTurns]; |
|
…… |
|
}; |
但上面给出的是声明而非定义,通常C++要求对任何东西的使用都要有定义式,但
像这种情况则可以例外,只要不取他们的地址就可以。
如果取地址,或者因为编译器的原因要求定义式,这定义如下:
const int GamePlayer::NumTurns; //将此式放进一个实现文件而非头文件 |
class常量已经声明了初值,这里就不在设了。
旧的编译器可能不支持以上语法,那么你可以把初值放在定义式中。
这又有例外了,编译器期间需要一个calss常量时(如数组scores[]的声明式),编译器又不允许“static整数型class常量”完成“in class”初值设定,可以改用“the enum hack”来实现。
如
class GamePlayer { |
|
private : |
|
enum { NumTurns = 5 }; |
|
int scores[NumTurns]; |
|
…… |
|
} |
emum hack的方法其实和#define又有些像了,例如不能取得地址,如果不想让人获得地址或者reference这样正好。
另外Enmus和,#define绝不会导致不必要的内存分配(为什么这么说?难道编译器不会为Enmus分配内存?#define不知在每次调用都会占一次内存吗?const只有一份拷贝,不管调用多少次,难道const比define还多费了内存??)
3)回到预处理器来,另一个常见的#define误用情况是以它实现宏(macros)。
宏看起来像函数,但不会招致函数调用(function call)带来的额外开销。
#define CALL_WITH_MAX(a, b) f((a)
>
(b) ? (a) : (b))
无论何时当你写出这种宏,必须记住为宏中的所有实参加上小括号,即使是加了括号,也还是会有问题。如
int a = 5, b = 0;
CALL_WITH_MAX(++a, b); //a被累加二次
CALL_WITH_MAX(++a, b+10); //a被累加一次在这里,调用f之前,a的递增次数竟然取决于"它被拿来和谁比较"!
用inline函数来解决这个问题
template inline函数(见条款30):
template < typename T> //由于我们不知道具体会操作什么类型,所以用模板 |
inline void callWithMax( const T& a, const T& b) //T是什么,所以采用 |
{ //pass by reference-to-const. |
f(a > b ? a : b); //见条款20. |
} |
对于单纯常量,最好以const对象或enums替换#defines。
对于形似函数的宏(macros),最好改用inline函数替换#defines