Effective C++在此条款中总结出两个结论

1.对于单纯常量,最好以const对象或enum替换#define

2.对于形似函数的宏,最好改用inline函数替换#define

接下来我们进行详细的探讨。

const替换#define的讨论

例如:

#define ASPECT_RATIO 1.653

原书给出的解释大意是:

你所使用的名称(ASPECT_RATIO)可能并未进入记号表(symbol table),原因也许是记号名称ASPECT_RATIO从未被编译器看见,也许在编译器开始处理源码之前他就被预处理器移走了。从而导致一个后果:当你运用此常量但获得一个编译错误信息时,这个信息也许会提到1.653而不是ASPECT_RATIO(因为所有的ASPECT_RATIO都被1.653代替),使得debug出现困难,因为你可能对1.653来自何处毫无概念,特别在多个文件都定义了ASPECT_RATIO时,无法确定是哪一个常量出了问题。

记号表:每个可重定位目标模块都有一个符号表,它包含m所定义和引用的符号的信息,在链接器的上下文中,有三种不同的符号: 1.由m定义并能被其他模块引用的全局符号 2.由其他模块定义并被模块m引用的全局符号 3.只被模块m定义和引用的本地符号
可重定位目标文件:     包含二进制代码和数据,其形式可以在编译时与其他可重定义目标文件合并起来,创建一个可执行目标文件。 

解决之道是以一个常量替换上述的宏:

const double AspectRatio = 1.653;

作为一个语言常量,AspectRatio肯定会被编译器看到,当然会进入记号表内。此外对浮点常量而言,使用常量可能比使用#define导致较小量的码,因为预处理器盲目将宏名称替换为1.653,可能导致目标码(object code)出现多份1.653,若改用常量绝不会出现相同情况。

以常量替换#define,有两种特殊情况值得注意:

1.定义常量指针。若要在头文件内定义一个指向常量的常量指针,需要些const两次

        const char* const pc = "c++";//指向常量字符串的常量char*型指针

一个小知识点是,string对象比char*类型的指针更合意,所以pc定义成下面的样式更好些

        const std::string pc("c++");//常量string对象

2.class类内的专属常量,为保证至多只有一个实体,必须声明为static。

class GamePalyer { private:    static const int NumTurns = 5;//常量声明式    int scores[NumTurns];//使用该常量 }

对于static类型的class专属常量,若它是整数类(例如int,char,bool),只要不取他们的地址,可以声明并使用它们而无须提供定义式。

如果必须用到定义式,必须在实现文件而不是头文件如下定义

const int GamePlayer::NumTurns;//NumTurns的定义

由于NumTurns已在声明时获得初值,因此定义时不可以再设初值。如果你的编译器不支持static成员在其声明式上获得初值,可以将初值放在定义式。

static const int NumTurns;//声明 const int GamePalyer::NumTurns = 5;//定义

以enum替换#define的讨论

当你在class编译期间需要一个class常量值,如果你的编译器不允许static整数型class常量完成类内初值设定,可使用enum。

class GamePlayer { private:     enum { NumTurns = 5 };     int scores[NumTurns]; }

这样做的好处是enum不允许取地址,有时这正是我们想要的。如果不想让别人获得一个pointer或reference指向你的整数常量,enum可以帮助实现这个约束。

inline替换#define的讨论

#define CALL_WITH_MAX(a,b) f((a) > (b> ? (a) : (b))

对于这种宏的调用,有时会发生不可思议的事情

int a = 5, b = 0; CALL_WITH_MAX(++a,b);//a被累加二次 CALL_WITH_MAX(++a,b+10);//a被累加一次

这时可以使用template inline函数避免这些缺陷

template<tyoename T> inline void callWithMax(cosnt T& a,cosnt T& b) {     f(a > b ? a : b); }

最新文章

  1. Sublime Text 3编译Sass - Sublime Text安装Sass插件
  2. Python正则化学习
  3. 字符编码笔记:ASCII,Unicode和UTF-8(转载)
  4. iOS开发——高级技术&amp;通讯录服务
  5. eclipse新建一个Android项目,就会报错android.support.v7.app.ActionBarActivity
  6. Qt label加边框
  7. High Performance Animations
  8. cygwin 的不同文件类型显示不同的颜色
  9. [SQL]循环插入数据,并且计算插入所用时间
  10. tomcat简介及原理解说
  11. window.showModalDialog 与window.open传递参数的不同?
  12. UVA_437_The_Tower_of_the_Babylon_(DAG上动态规划/记忆化搜索)
  13. [BZOJ 3129] [Sdoi2013] 方程 【容斥+组合数取模+中国剩余定理】
  14. 14.5.5 Deadlocks in InnoDB
  15. 响应式设计的5个CSS实用技巧
  16. 打造属于自己的支持版本迭代的Asp.Net Web Api Route
  17. tomcat 与 java web中url路径的配置以及使用规则详情(长期更新)
  18. C# 各种控件实现可拖动和调整大小
  19. 【译】第43节---EF6-自定义约定
  20. WordPress主题开发:数据调用

热门文章

  1. Advanced Plugin Concepts
  2. 如何不使用 submit 按钮来提交表单?
  3. linux 重启 启动 apache服务
  4. Python之基本排序算法的实现
  5. oracle 之分析函数 over (partition by ...order by ...)
  6. 学习笔记 - Manacher算法
  7. Redis Cluster Notes
  8. STM32(1)——使用Keil MDK以及标准外设库创建STM32工程
  9. buck型DC-DC分析
  10. centos系统安装后无法稳定连接wifi的解决方法