#define ASPECT_RATIO 1.653 

记号名称ASPECT_RATIO可能未被编译器看见,也许在编译器开始处理源码之前就被预处理器移走了,也许获得一个编译错误时候,可能提到1.653而不是ASPECT_RATIO,如果ASPECT_RATIO被定义在一个非你所写的头文件内,那你对1.653已经它来自何处毫无概念,于是你将因为追踪它而浪费时间。

你所使用的名称可能并未进入记号表

解决之道是以一个常量替换宏(#define):

const double AspectRatio = 1.653; 

 

当我们以常量替换#defines时,有两种特殊情况值得说说。

第一是定义常量指针(constant pointers)。由于常量定义式通常被放在头文件内(以便被不同的源码含入),因此有必要将指针(而不只是指针所指物)声明为const。例如若要在头文件内定义一个常量的char*-based字符串,你必须写const两次:

const charconst authorName = "Scott Meyers"

 string对象通常比其前辈char*-based合宜,所以上述的authorName往往定义成这样更好些:

const charconst authorName = "Scott Meyers"

第二值得注意的是class专属常量。为了将常量的作用域(scope)限定于class内,你必须让它成为class的一个成员;而为了确保此常量至多只有一份实体,你必须让它成为一个static成员:

  1. class GamePlayer 
  2. private: 
  3.   static const int NumTurns = 5;//常量声明式 
  4.   int scores[NumTurns];         //使用该常量 
  5. };

然而你看到的是NumTurns的声明式而非定义式,通常C++要求你对你所使用的任何东西提供一个定义式,但如果它是个class专属常量又是static且为整数类型,则需要特殊处理,只要不取它们的地址,你可以声明并使用它们而无须提供定义式。但如果你取某个class专属常量的地址,或纵使你不取其地址而你的编译器却坚持要看到一个定义式,你就必须另外提供定义式如下:

 

  1. const int GamePlayer::NumTurns;//NumTurns的定义 
  2. //由于class常量已经在声明时获得初值,因此定义时不可以再设初值 

 

我们无法利用#define创建一个class专属常量,因为#defines并不重视作用域。#defines也不能够提供任何封装性。

如果你的编译器不支持上述语法,你也可以将初始值放在定义式里:

 

  1. class CostEstimate 
  2. {     
  3. private:     
  4.   static const double FudgeFactor;//static class 常量声明位于头文内    
  5. //...  
  6. }; 
  7.   
  8. const double CostEstimate::FudgeFactor = 1.35;//static class    
  9. //常量定义位于实现文件内 

 

一个属于枚举类型(enumerated tyoe)的数值可权充ints被使用,于是GamePlayer可定义如下:

 

  1. class GamePlayer 
  2. private:   
  3.   enum{NumTurns = 5};     
  4.   int scores[NumTurns];     
  5. //...     
  6. }; 

 

 

enum hack的行为某方面说比较想#defines而不想const]

  1. //以a和b的较大值调用f     
  2. #defines CALL_WITH_MAX (a,b) f((a)>(b) ? (a) : (b)) 
  3. //------- 
  4. int a = 5, b = 0;     
  5. CALL_WITH_MAX(++a, b);   //a被累加两次     
  6. CALL_WITH_MAX(++a, b+10);//a被累加一次 

 

 

用template inline函数 

 

  1. template<typename T>     
  2. inline void callWithMax(const T& a, const T& b)     
  3. {     
  4.   f((a)>(b) ? (a) : (b));     
  5.   

 

有了consts,enums 和inlines 我们对预处理器的需求降低了,当并非完全消除了,#include仍然是必需品,而#ifdef/#ifndef也很重要。

 

请记住

  1. 对于单纯常量,最好以const对象或enums替换#defines
  2. 对于形似函数的宏,最好改用inline函数替换#defines