##常规变量

c++里面的#define后面的定义部分,是不算代码的一部分的。所以如果你使用#define:

#define ASPECT_RATIO 1.653

你希望这个代号ASPECT RATIO这个代号是能够被编译器加入到记号表(symbol table)里面,如果调试的时候,这个部分出现问题,能够很快的发现出来。但是很多时候我们的预处理器会把这个变量移除,只保留了一个1.653的常量,如果Debug的时候这个常量出现了错误,你是很难定位到自己需要修改代码的地方的,这就会造成我们在使用中Debug的时候很不方便。我们可以使用另外的方式来定义

1
const double AspectRatio = 1.653;

修改之后,AspectRatio这个常量肯定会写入到记号表里面,是可以被编译器找到的。另外使用#define 可能会造成我们的代码里面有很多的object code 为 1.653, 但是使用const的方式,我们的代码里面就只会有一个AspectRatio

如果是常量指针(constant pointers), 由于我们的常量一般是定义在头文件中的,所以我们需要将指针声明为const。如:

const char* const authorName = "Scott Meyers";

这里可以修改为String类型,使用String来存储字符串会比char*更加的合适,可定义为const std::string authorName("Scott Meyers");

Class内部专属变量

问题:限制常量的作用域是在Class内部,这样就要将这个常量作为Class的一个membeer, 这样就能够确保这个常量至多只有一个实体,并且必须将其声明为static member

1
2
3
4
5
class  {
private:
static const int NumTurns = 5;
int scores[NumTurns];
}

因为这里面static const int NumTurns = 5;这是放在类的声明里面的,在这里就是一个变量的声明,并不是变量的定义,在内存里面是没有的。但是c++如果你在其他地方去使用的话,那是需要我们对这个进行先定义在使用的。如果要在其他地方使用,就需要提供一个定义:

const int GamePlayer::Numturns;

这个就可以放在你需要使用GamePlayer::NumTurns这个变量的文件里面,放在*.cpp文件里,而不是*.h文件中。

注明:由于在类的声明中已经给GamePlayer::NumTurns进行了赋值操作,所以在这里单独直接定义就可以调用声明进行赋值操作。

另外一种针对老式编译器不支持上述语法的解决方法:

1
2
大专栏  Book. Effective C++ item2-尽量使用const, enum, inline替换#define3
4
5
6
7
8
//在头文件中
class CostEstimate {
private:
static const double FudgeFactor; //static class 常量声明
...
}
//在实现文件中去做
const double CostEstimate::FudgeFactor = 1.35;

上面这种方式可能问题:class在编译区间需要一个class的长两只,就是编译器不允许static const int a 完成初始设定,这样我们就要使用到 the enum hack的方式进行补偿。理论:一个属于enumerated type的数值是可以当成ints来使用的

1
2
3
4
5
class  {
private:
enum {NumTurns = 5};
int scores[Numturns];
}

说明: emum hack定义的内容,是不能够取地址的,取地址的操作是不合法的,而取#define的地址也是不合法的,但是取一个const的地址是合法的。如果不想让其他人获得这个pointer或者reference指向你的整数变量,enum就可以很好的实现这个功能。

emum#define是绝对不会导致非必要的内存分配的。

实现宏定义

宏定义看起来像一个函数,但是不会导致函数的调用导致的额外开销,比如:

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

首先,写这样的宏必须为所有的实参都加上小括号,否则其他地方调用的时候会出现问题。但即使加上了,如果你实现这样的代码:

1
2
3
int a = 5, b = 0;
CALL_WITH_MAX(++a,b);
CALL_WITH_MAX(++a,b+10);

在调用之前,a会递增之后在去调用,并且是否递增取决与它和谁比较。

小结

  • 对于单纯变量,使用const对象或者enums替换#define
  • 形如函数的宏,修改为inline函数替换#define

Book. Effective C++ item2-尽量使用const, enum, inline替换#define的更多相关文章

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

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

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

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

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

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

  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. 条款02:尽量以const,enum,inline替换#define

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

  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没有进入标识符列 ...

随机推荐

  1. i春秋web作业2.26

    Web安全工程师(入门班) [全国线上入门班53期]课后作业   2020-2-26 DorinXL   1)为什么说js校验是一种不安全的校验方式? js校验不安全,是因为用户很容易通过控制台删除或 ...

  2. 吴裕雄--天生自然 pythonTensorFlow自然语言处理:Seq2Seq模型--训练

    import tensorflow as tf # 1.参数设置. # 假设输入数据已经用9.2.1小节中的方法转换成了单词编号的格式. SRC_TRAIN_DATA = "F:\\Tens ...

  3. 爬虫笔记(十四)——BeautifulSoup库

    Beautifulsoup库: 该库是python语言写的,主要功能是将html.xml格式的数据对象解析成"标签树",并进行遍历和维护,即可以从网页抓取数据. 借鉴的html是妹 ...

  4. tesseract系列(4) -- tesseract训练问题总结

    1. 每次训练模型删除目录下,上述重复的名字 2. 生成inttemp.pffmtable文件的时候,如果下述命令(1)不行的话,或者报错,使用命令(2) (1)mftraining -F font_ ...

  5. Linux集群软件安装实战

    一.需求和思路 1. 需求描述 公司有N个节点的集群,需要统一安装一个软件(jdk)需要开发一个脚本程序,实现对集群中的N个节点批量自动下载.安装jdk 2. 思路 1)编写一个启动脚本,用来发送一个 ...

  6. 工具类BitMap 把网络URL图片转换成BitMap

    代码不复杂,直接把完整代码贴上. 这次是用到很旧的HttpURLConnection,那为什麽会用这个,因为我本来想转回okhttp的,可实在没时间转,项目就已经做下去了,结果转不回来. packag ...

  7. Qt 信息提示框 QMessageBox

    information QMessageBox::information(NULL, "Title","Content",QMessageBox::Yes | ...

  8. C++语言堆栈的详细讲解

    本文主要向大家介绍了C++语言堆栈的详细讲解,通过具体的内容向大家展示,希望对大家学习C++语言有所帮助. 一.预备知识—程序的内存分配 一个由c/C++编译的程序占用的内存分为以下几个部分 1.栈区 ...

  9. python后端面试第六部分:git版本控制--长期维护

    ################## git版本控制 ####################### 1,git常见命令作用 2,某个文件夹中的内容进行版本管理:进入文件夹,右键git bash 3, ...

  10. IE11阅读视图:带给你静心饕餮阅读大餐的片刻

    编者按:又到读书日,今天你挤出时间读书了吗?如今,越来越多人在习惯电子阅读,然而总难逃眼花缭乱的干扰信息.Internet Explorer 11新增阅读视图功能,一键开启,给你带给你静心饕餮阅读大餐 ...