笔记:Perfer consts,enums,and inlines to #define

来源:互联网 发布:淘宝开店装修教程视频 编辑:程序博客网 时间:2024/05/16 06:55

 #define 或许不被视为语言的一部分。

#define ASPECT_RATIO 1.63

ASPECT_RATIO也许从未被编译器看见,也许在编译器开始处理源码之前就被预处理器移走了。
于是ASPECT_RATIO有可能没有进入符号表(symbol table).
要是出现错误就不好调试。
可能出现两个错误,错误信息说1.63而不是ASPECT_RATIO。或者这个定义出现在另外的头文件,出现这个错误可能在符号调试器中(symbolic debugger),但是因为ASPECT_RATIO不在符号表中出现错误。

解决的办法是用常量代替上述的宏(#define)

const double AspectRatio = 1.63           
//大写名称通常用于宏,这里是变量。
作为一个常量,AspectRatio肯定会被编译器看见,也就会进入符号表内。
此外对浮点常量(floating point constant)而言,使用常量可能比使用#define导致较小量的码,因为预处理会盲目将宏ASPECT_RATIO替换成1.63,导致目标码(object code)出现多份1.63,若改用常量就不会出现这样的情况。

当使用常量替换#define,有两种特殊的情况.
1,定义常量指针(constant pointers)
由于常量定义式通常被放在头文件内让不同的源代码使用,因此有必要对指针(不仅仅是指针所指向的对象)声明为const。(防止被改动)
例如若要在头文件定义一个常量的基于char*的字符串,必须写const两次:
const char* const authorName = "Scott Meyers";
关于const的意义和使用(特别是与指针结合时),在条款3有详细的讨论。
string对象通常比char*-based 合适,所以下面定义更好:
const std::string authorName= "Scott Meyers";

2,class专属常量。
若要使某个常量的作用域(scope)限制于class内,必须让它成为class的一个成员。
若是要使这个常量只有一份实体,就必须让其是static成员。

class GamePlayer
{
private:
 static const int NumTurns = 5;   //这个表达式是常量声明式,非定义式。
 int scores[NumTurns];    // 使用了该常量
 。。。
};

C++要求你对你所使用的任何变量都提供一个定义式,如果它是class的专属常量,还是static的,并且类型为整数类型(integral type,例如int,char,bool),要特殊处理。只要不取他们的地址,可以只声明并且使用而不需要再提供一个定义式。
若是要取class专属常量的地址就必须提供一个定义式
const int GamePlayer::NumTurns;           //NumTurns的定义式。为什么没有赋值了?
这个定义式放在CPP文件中,由于class常量在声明时候已经获得初值,因此定义时不需要再设初值。

在VS 2005中要是提供了定义式则会出现重复定义的错误。
用G++编译器则是对的。

不过一般旧的编译器也是不支持以上的语法,不允许static成员在其声明式上获得初值。则只有把初值放在定义式中。
比如
class CostEstimate
{
private:
static const double FudgeFactor;   //static const  常量声明 位于头文件
};

const double CostEstimate::FudgeFactor = 2.33;          //static const 常量定义位于实现文件内(cpp文件)

 

再就是在类中(in-class)的初值设定也只允许对整数常量进行,其他的数据类型必须在定义式中进行赋初值。

有一种例外就是当class编译期间需要一个class的常量值,就需要一种补偿的做法。
比如说class GamePlayer中的score的数组声明式中必须要知道其大小。编译器不允许static整数型class常量 完成的在类中的初值设定,就可以改用“the enum hack”补偿做法。
这个的理论基础是:“一个属于枚举类型的数值可以权充int被使用”,于是GamePlayer可以定义如下:

class GamePlayer
{
private:
    enum {NumTurns = 5};             //the enum hack  --- 令NumTurns成为5的一个记号名称
 int scores[NumTurns];    
 。。。
};


基于一些理由enum hack值得我们了解。
1, enum hack的行为某方面比较像 #define而不像 const,有时候这样就是你所想要的。取const的地址是合法,去enum就不合法。如果你不想别人活着一个指针或引用指向你的某个整数变量,enum是个好的选择,实现了这个约束。(条款18讲解了“通过撰写代码来实施设计上的约束条件”)。

2,Effective C++上说是为了实用主义。许多代码用了它,所以应该了解。 事实上“enum hack”是template metaprogramming(模板元编程,48)的基础技术。


最后用inline代替宏函数。(条款30详细说明inline函数)


记住:
1,对于单纯常量,最好以const对象活着enum替换 #define
2,对于形似函数的宏,最好改用inline函数替换 #difine

原创粉丝点击