换一种说法就是宁可以编译器替换预处理器

举例

#define ASPECT_RATIO 1.653
  • 记号ASPECT_RATIO也许从未被编译器看见;也许在编译起开始处理源码前它就被预处理器移走了,于是它并没有进入符号表,当出现编译错误的时候会提示1.653,但是不会提示ASPECT_RATIO。

  • 解决办法就是用一个常量替换宏(#define):

const double AspectRatio = 1.653;

常量替换宏的两种特殊情况

1. 常量指针
  • 常量定义通常被放在头文件内(以便被不同的源码含入)
  • 常量的(不变的)char*-based:
const char* const authorName = "Scott Meyers";
const std::string authorName("Scott Meyers"); (C++最好用这种方式)
2. class专属常量
  • 为了将常量的作用域限制于class内,必须让它成为class的一个成员;而为确保此常量至多只有一份实体,必须让它成为一个static成员:
class GamePlayer  {
private:
static const int NumTurns = 5; // 常量声明式
int scores[NumTurns]; // 使用该常量
}
  • 如果编译器坚持要看到一个定义式,那么就必须提供以下定义,并且把它放入实现文件而非头文件,因为class常量已在声明时获得初值,因此定义时不可以再设初值。
const int GamePlayer::NumTurns;   // NumTurns的定义;
  • 无法利用#define 创建一个class专属常量,因为#define并不重视作用域(scope)。一旦宏被定义,它就在其后的编译过程中有效(除非在某处被#undef)。

  • 旧式编译器也许不支持以上语法,它们不允许static成员在其声明式上获得初值。此外所谓"in-class 初值设定",也只允许对整数常量进行。应该改成如下形式:

class CostEstimate {
private:
static const double FudgeFactor; // static class 常量声明位于头文件
};
const double CostEstimate::FudgeFactor = 1.35; // 位于实现文件内
  • 如果编译起不允许“static 整数型class常量”完成"in class 初值设定",可改用所谓的"the enum hack" 补偿做法。其理论基础是“一个属于枚举类型的数值可权充ints被使用”,见如下定义:
class GamePlayer {
private:
enum {NumTurns = 5};
int score[NumTurns];
}

用inline替换形似函数的宏(macros)

// 以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被累加两次
CALL_WITH_MAX(++a, b + 10); // a被累加一次
template<typename T>
inline void callWithMax(const T& a, const T& b) { // 由于我们不知道T是什么,所以采用pass by reference-to-const
f(a > b ? a:b);
}

总结

  • 有了const,enum,inline,我们对预处理器(特别是#define)的需求降低了,但并非完全消除。#define仍然是必需品,而#ifdef/#ifndef也继续扮演控制编译的重要角色。

请记住

  • 对于单纯常量,最好以const对象或enums替换#define
  • 对于形式函数的宏(macros),最好改用inline函数替换#define

Effective C++ 条款02:尽量以const,enum,inline替换 #define的更多相关文章

  1. Effective C++学习笔记 条款02:尽量以const,enum,inline替换 #define

    尽量使用const替换 #define定义常量的原因: #define 不被视为语言的一部分 宏定义的常量,预处理器只是盲目的将宏名称替换为其的常量值,导致目标码中出现多分对应的常量,而const定义 ...

  2. Effective C++阅读笔记_条款2:尽量以const,enum,inline替换#define

    1.#define缺点1 #define NUM 1.2 记号NUM可能没有进入记号表,在调试或者错误信息中,无法知道1.2的含义. 改善:通过const int NUM = 1.2; 2.#dein ...

  3. 条款02:尽量以const,enum,inline替换#define

    目录 1. 总结 2. 使用const常量或enum替换宏常量 class外部的常量指针 class专属常量 1. 总结 对于单纯常量,最好以const常量或enum替换#define 对于宏代码段, ...

  4. 读书笔记_Effective_C++_条款二:尽量以const, enum, inline替换#define

    其实这个条款分成两部分介绍会比较好,第一部分是用const和enum替换不带参的宏,第二部分是用inline替换带参的宏. 第一部分:用const和enum替换不带参宏 宏定义#define发生在预编 ...

  5. 条款2:尽量以const, enum, inline替换#define

    原因: 1. 追踪困难,由于在编译期已经替换,在记号表中没有. 2. 由于编译期多处替换,可能导致目标代码体积稍大. 3. define没有作用域,如在类中定义一个常量不行. 做法: 可以用const ...

  6. NO.2: 尽量以const,enum,inline 替换 #define

    1.首先#define 定义不重视作用域(scope),虽然可以#undef控制,但是不美观,还存在多次替换的问题,以及没有任何封装性. 2.const XXX_XX,保证其常量性以及可控的作用域,如 ...

  7. Effective C++ -----条款02:尽量以const, enum, inline替换 #define

    class GamePlayer{private: static const int NumTurns = 5; int scores[NumTurns]; ...}; 万一你的编译器(错误地)不允许 ...

  8. Effective C++之条款2:尽量以const enum inline替换 #define

    本文的标题也可以改成“用编译器替换预处理器”: const double AspectRatio = 1.653; //最好使用上述代码替换下述代码: #define ASPECT_RATIO 1.6 ...

  9. 条款2:尽量使用const ,enum,inline替换define

    宁可使用编译器而不用预处理器 假设我们使用预处理器: #define ABC 1.56 这标识符ABC也许编译器没看到,也许它在编译器处理源码前就被预处理器移走了,于是“标识符”ABC没有进入标识符列 ...

  10. Book. Effective C++ item2-尽量使用const, enum, inline替换#define

    ##常规变量 c++里面的#define后面的定义部分,是不算代码的一部分的.所以如果你使用#define: #define ASPECT_RATIO 1.653 你希望这个代号ASPECT RATI ...

随机推荐

  1. centos 6.5 安装图形界面【转】

    最近想在centos 6.5上安装图形界面,在网上找到了方法.[原文链接] CentOS6相对于CentOS5的安装有了不少的进步,有不少默认的选项可以选择,如: Desktop :基本的桌面系统,包 ...

  2. hdu4328(经典dp用悬线法求最大子矩形)

    http://wenku.baidu.com/view/728cd5126edb6f1aff001fbb.html 关于悬线法,这里面有详解. 我当时只想到了记录最大长度,却没有想到如果连最左边和最右 ...

  3. 广药帅气外教~看妹纸如何HOLD住

    看他吉他弹的好,看来我要努力练习我的吉他了,一个月了没有任何长进啊. shit~!

  4. 【IDEA】重装基本设置+插件安装

    基本配置:2.1 显示:2.1.1.选中展示Toolbar2.1.2.显示内存占用:2.1.3.显示行号和方法线:2.1.4.代码软分行:2.2.修改快捷键:2.2.1 修改Ctrl + D 快捷键: ...

  5. root Permission denied

    w 遇见现象,原因待查

  6. 短URL DH 密钥交换算法

    w  追问:0-短URL 的时效性,(比如微信个人账户的永久二维码和群的约7天时效二维码):1-0中的时效性对于算法选择的影响,比如简单的HAS映射.sha1.md5......   https:// ...

  7. Delphi日期设置为NULL

    在某些情况下,需要将日期字段的值置空,这种操作比较麻烦.在操作的时候,可将变量的值(t:TDateTime)设置为0,在操作的过程中进行判断,当t的值为0或-1的时候,时间值为1899年的Delphi ...

  8. python引入同一目录下的py文件

    python引入同一目录下的py文件 注意:python2和python3的包内import语法有区别,下面介绍一下python3的包内import语法 例如在admin.py文件中要引入dealco ...

  9. 【MonogDB】The description of index(二) Embedded and document Index

    In this blog, we will talk about another the index which was called "The embedded ". First ...

  10. 基本运算符与流程控制(Day5)

    一  运算符 1.算数运算 2.比较运算 3.赋值运算 4.逻辑运算 and注解: 在Python 中,and 和 or 执行布尔逻辑演算,如你所期待的一样,但是它们并不返回布尔值:而是,返回它们实际 ...