#define ASPECT_RATIO 1.653
Probelms:
ASPECT_RATIO不回进入记号表(symbol table),在编译前被预处理器拿走了,这导致在编译错误时无法根据符号追踪来源。
预处理器“盲目地将宏名称ASPECT_RATIO替换为1.653”可能导致目标码(object code)出现多分1.653.
//建议以一个常量替换上述宏(#define)
const doubel AspectRatio = 1.653;//大写一般用作宏定义,这里更改变量写法
以常量替换**#define**的两种特殊情况:
1.定义常量指针
为了便于被不同的源码含入,常量定义式通常放在头文件中,因此将常量指针声明为const就变得非常有必要。
//在头文件中定义一个不变的char*字符串 const char* const AspectName = "Suger Master";
//采用string对象替换char* const std::string AspectName = ("Suger Master");
2.class专属常量
为了常量的作用域(scope)限制在class之内,就必须让常量成为class的一个成员(member);为了确保这个常量至多只有一份实体,就必须让它成为static成员。
class ScoPlayer { private: static const int NumTurns = 5; //常量声明式 int scores[NumTurns]; //使用该常量 }
解释:为何这里是声明式而非定义式?(通常C++要求对你所使用的任何东西提供一个定义式)
回答:当属于class专属常量又是static且为整形(integral type),需特殊处理。当不取地址时,可以声明并使用而无需提供定义式;当需要某个class专属常量的地址,或不取地址而编译器却(不正确地)坚持要看到一个定义式~~什么鬼?~~时,你必须提供如下定义式:const int ScoPlayer::NumTurns; //NumTurns的定义; //解释:为什么没有赋值? //回答:把这个式子放在一个实现文件而非头文件。因为class常量已在声明时获得初值(例如前面代码声明时设初值为5),所以不可以再设初值
注意:由于#define并不重视作用域(scope)。一旦宏被定义,她就在其后的编译过程中有效(除非在某处被#undef
不太懂)。所以,这意味着#define不仅不能被用来定义class专属常量,也不能提供任何封装性,即没有所谓的private #define这样的东西。const成员变量是可以被封装的。//旧式编译器如果不支持上述语法 class CostEstimate{ private: static const double FudgeFactor; //static class 常量声明,位于头文件内 }; const double CostEstimate::FudgeFactor =1.35; //static class 常量定义,位于实现文件内
万一编译器(错误地)不允许“static 整数型class常量”完成“in class"初值设定”,可改用所谓的 “the enum hack” 补偿做法。
“the enum hack 补偿做法”
其理论基础是:一个属于枚举类型(enumerated type)的数值可权当ints 被使用,于是ScoPlayer可定义为:
class Scoplayer{ private: enum{ NumTurns = 5}; //"the enum hack"——令NumTurns成为5的一个记号名称。 int scores[NumTurns]; //使用该定义
enum hack 更像#define 而不像const。例如:const可以取地址,而去一个enum地址就不合法,取一个#define的地址通常也不合法。
对于形似函数的宏(macros)最好改用inline函数替换define.
//以a和b的较大值调用f
#define CALL_WITH_MAX(a,b) f((a) >(b) ? (a) :(b))
int a = 5,b=0;
CALL_WITH_MAX(++a, b); //a被累加二次
//注释:比较时a为累加一次;比较为true,此时a再累加一次,结果为7
CALL_WITH_MAX(++a,b+10); //a被累加一次
//注释:比较我false,只累加一次
为了在获得宏带来的效率以及一般函数的所有可预料行为和类型安全性(type safety),我们可以采用template inline函数
template<typename T>
inline void callWithMax(const T& a, const T& b)
{
f(a > b ? a : b);
}
//一个“class内的private inline 函数”
总结:有了consts、enum和inline,我们可以降低对预处理器(特别是#define)需求,但并非完全消除,现在我们仍需要#ifdef/#ifndef继续扮演控制编译的重要角色。