尽量以const,enum,inline替换#define
由于#define不被视为语言的一部分,故你可以编译器替换预处理器,即使用const,enum,inline替换#define。
宏定义的名称可能不能进入记号表,从而在编译时报处错误,错误的名称且可能与定义的名称不同,而与值相同,从而导致查找错误较难。而解决此问题,可以使用常量来替换宏。如定义了如下宏:#define PI 3.14,改为const double Pi = 3.14即可。此时Pi肯定会被编译器看见,从而进入记号表内。此外,对浮点常量而言,使用常量可能比用#define导致较小量的码,因为预处理器“盲目地将宏名称PI替换为3.14可能导致目标码出现多一份3.14,而改用常量Pi绝不会出现相同情况。
以常量替换#define时,两种特殊情况:
1)定义常量指针。由于常量定义式通常被放在头文件内(以便被不同的源码含入),因此有必要将指针(而不只是指针所指之物)声明为const。如在头文件中定义一个常量不变的char -based字符创,必须写const两次。const char const ath = “yzhang”。string对象通常比其前辈char*-based更合适,故这样定义更好:const std::string ath(“yzhang”);
2)class专属常量。为将常量的作用于限制在class内,必须让它成为class的一个成员;为确保此常量至多只有一份实体,必须让它成为一个static成员。举例如下:
class Game
{
private:
static const int Num = 5; // 常量声明式
int scores[Num]; // 使用该常量
};
const int Game::Num; // Num的定义式,未赋值
(如果取某个class专属常量的地址,或纵使不取其地址而你的编译器却不正确地坚持要看到一个定义时,就必须提供定义式。
注意:无法利用#define创建一个class专属常量,因为#define并不重视作用域。一旦宏被定义,它就在其后的编译过程中有效(除非在某处被#undef)。表明#define不仅不能用来定义class专属常量,也不能提供任何封装性,如private #define是不对的。而const变量可以被封装。
如果编译器不允许static整数型class常量完成in class初值设定,可改用“the enum hack”补偿。原因:一个属于枚举类型的数值可权冲ints被使用。举例如下:
class Game
{
private:
enum { Num = 5 }; // 令Num成为5的一个记号名称
int scores[Num];
};
1)enum hack的行为某方面说比较像#define而不像const。取const地址合法,但取enum的地址和#define的地址都不合法。
2)如果不想让别人获得一个pointer或reference指向你的整数常量,enum可以实现这个约束。enums和#defines绝不会导致非必要的内存分配。
3)enum hack比较实用。事实上,enum hack是template metaprogramming(模板元编程)的基础技术。
宏看起来像函数,但不会招致函数调用带来的额外开销。无论何时写宏时,必须记住宏中的所有实参加上小括号,否则某些人在调用这个宏时可能会遭遇麻烦。
实用内联函数template inline,可以获得宏带来的效率以及一般函数的所有可预料行为和类型安全性。
template<typename T> inline void call(const T &a, const T &b)
{
f(a > b ? a : b);
}
template产生一群函数,每个函数接受两个同类型对象,其中较大的调用f
此函数遵守作用域和访问规划。可以写class内的private inline函数
虽然有consts,enums,inlines,降低预处理(#define)的需求,但#include仍是必需品,#iedef/#ifndef也扮演重要角色。
**注意:**1)对于单纯常量,最好以const对象或enums替换#defines;2)对于形似函数的宏,最好改用inline函数替换#defines。
参考:Effective C++ 侯捷