以下,是对const,enum,inline的一系列测试
----《effective c++》条款二 : 尽量以const,enum,inline 替代#define
例如:
#define PI 3.1415926
这个记号名称PI,也许不会被编译器所看到,也许在编译器开始处理源码之前它就被预处理器移走了。
于是在生成.o可重定义目标文件时,记号名称PI有可能没进入记号表(.symtab)内,当你运用此变量,
但获得一个编译错误信息的时候,错误也许会提到3.1415926而不是PI,
如果PI存在在不是你自己写的头文件中,你将非常难以对其进行追踪,进而浪费你的时间。
解决之道是以一个常量(const)替换上述的宏(#define):
const double Pi = 3.1415926; // 全大写名称通常用于宏定义
作为一个全局常量,这个变量必然会在编译的时候被计入记号表内
当要设置一个class的专属常量时,
为了将一个常量的作用域限制在一个class内,你必须让它成为一个class的成员(number):
而为了保证此常量只在内存中存在一个实体,
你应该让它成为一个static成员,如下:
class A{
private:
static const int Num = 12; //常量声明式
int perple[Num];
...
};
当然这只是个声明式,通常c++还需要你提供所使用的任何东西的定义式,
但如果它是个class专属static常量,且为整型,则可以声明并使用它而不需要提供声明式,
但是,如果你想在后面使用和访问这个整型常量的地址,则需要在.c(实现文件)文件中另外提供定义:
const int A::Num; // Num的定义
因为这个Num已经在生命中得到了初值,因此定义时不可以再设置初值
(只限制于整型,当然有些编译器也不支持整型在声明中赋予初值)
相反的,用#define则无法限制作用域,不能定义为一个class的专属常量,
也不能给一个class提供任何的封装性。如果你的编译器不支持上述语法,则可以将初值放在定义式:
// A.h
class A{
private:
static const int Num; //static class常量声明
int perple[Num]; //位于头文件内
...
};
//A.cpp
const int // static class常量定义
A::Num = 12; // 位于实现文件内
如果你的编译器不支持使用“static 整数型 const 常量” 完成类中的数组长度设定,
可改用“the enum hack”补偿做法,因为一个属于枚举类型的数值可以被当作int const
使用”,于是上述代码可以定义如下:
class A{
private:
enum{ Num = 5};
int perple[Num];
...
};
解决问题
当再次回到预处理器,另一个常见的#define
误用情况是以它实现宏。宏看起来像函数,
但不会找只函数调用带来的额外开销,
下面一个宏带着宏实参,调用函数f , 如下:
//记住为宏内所有的实参加上小括号
#define CALL_MAX(a,b) f((a)>(b)?(a):(b))
但即便为所有实参加上小括号,还是会导致不可思议的事情:
int a=5,b=5;
CALL_MAX(++a,b);//a被累加一次
CALL_MAX(++a,b+10);//a被累加两次
在这里,a的递增次数,竟然取决于“它和谁比较”
还好,你可以获得宏带来的效率,还可以避免出现以上的错误,
这要求你写出template inline(模版内联函数):
template <typename T>
inline void Call_Max(cont T& a,const T& b){
f(a>b?a:b);
所以,综上所述,最好以const
对象或enum
替换#define
对于形似函数的宏,则最好以inline
函数替换。
以上