##常规变量

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. HTTP协议解析小白文

    1. 什么是HTTP协议? HTTP协议是Hyper Text Transfer Protocol(超文本传输协议)的缩写,是用于从万维网(WWW:World Wide Web )服务器传输超文本到本 ...

  2. java常用工具类(二)

    1.FtpUtil package com.itjh.javaUtil; import java.io.File; import java.io.FileOutputStream; import ja ...

  3. 吴裕雄--天生自然 PYTHON3开发学习:JSON 数据解析

    import json # Python 字典类型转换为 JSON 对象 data = { 'no' : 1, 'name' : 'Runoob', 'url' : 'http://www.runoo ...

  4. python程序的打开运行方式

    python程序的运行方式大致可以分为两种,一种是直接通过python解释器直接解释型运行,另外一种是先把python程序编译为二进制文件再运行. .源代码 -python源代码的文件以"p ...

  5. CentOS7离线安装MySQL8.0

    CentOS7离线安装MySQL8.0 卸载软件 rpm -e --nodeps 要卸载的软件包 root@jacky zookeeper]# rpm -e --nodeps java-1.6.0-o ...

  6. python_8_集合

    1.集合:可变集合set,不可变集合frozenset,集合是无序不重复的 set('hello') set9[1,2,3,4]) set((1,2,3)) 2.添加元素 > add:将元素整体 ...

  7. day03-函数

    形参:位置参数:必须传 *args:动态参数,可以接收任意多个位置参数 默认值参数:可以传也可以不传 **kwargs:动态参数,可以接收多个关键字参数. 实参:按照位置传参,按照关键字传参. #顺序 ...

  8. as such 位于句首

  9. 关于Apache Commons-IO的使用

    commons-io是一款处理io流的工具,封装了很多处理io流和文件的方法,可以大大简化我们处理io流和操作文件的代码.从common-io的官方使用文档可以看出,它主要分为工具类.尾端类.行迭代器 ...

  10. bzoj 3450 Tyvj1952 Easy (概率dp)

    3450: Tyvj1952 Easy Description 某一天WJMZBMR在打osu~~~但是他太弱逼了,有些地方完全靠运气:(我们来简化一下这个游戏的规则有n次点击要做,成功了就是o,失败 ...