##常规变量

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. 多标签图像分类任务的评价方法-mAP

    http://blog.sina.com.cn/s/blog_9db078090102whzw.html 多标签图像分类(Multi-label Image Classification)任务中图片的 ...

  2. CentOS 7 准备 Superset 环境

    安装 anaconda 和 superset 下载 anaconda 软件: https://repo.anaconda.com/archive/Anaconda3-2019.10-Linux-x86 ...

  3. More 'long-life' plastic bags being used

    1 1.1 roll out v. 推广,或实行 1.2 pilot v. 试行 n. 飞行员 1.3 bags for life 可重复使用的环保购物袋 2 2.1 How many times a ...

  4. Spring Boot使用Liquibase最佳实践

    Liquibase问题 随着项目的发展,一个项目中的代码量会非常庞大,同时数据库表也会错综复杂.如果一个项目使用了Liquibase对数据库结构进行管理,越来越多的问题会浮现出来. ChangeSet ...

  5. 字典 -> model

    1.使用KVC init(dict : [String : Any]) { super.init() setValuesForKeys(dict) } override func setValue(_ ...

  6. ACM-ICPC Nanjing Onsite 2018 I. Magic Potion

    题意:类似二分图匹配给的题目,不过这次在这里给出了k,表示没人可以再多一次匹配机会,这次匹配不能用上一次被匹配的对象 分析:不能用匈牙利做俩次匹配,因为俩次的最大匹配并不等价于总和的匹配,事实证明,你 ...

  7. html为什么用雪碧图的优缺点

    CSS Sprite(雪碧图/精灵图) 1          概念解释 将小图标和背景图像合并到一张图片上,然后利用css的背景/定位来显示需要显示的图片部分. 2           优点 ① 减少 ...

  8. nginx做正向代理搭建bugfree

    下载地址: Nginx下载地址:http://download.csdn.net/detail/terrly88/9099117 bugfree下载地址:http://download.csdn.ne ...

  9. 信息检索盛会 微软“领衔主演”——记ACM SIGIR 2013信息检索国际会议

    微软"领衔主演"--记ACM SIGIR 2013信息检索国际会议" title="信息检索盛会 微软"领衔主演"--记ACM SIGIR  ...

  10. Rearrangement

    In a two dimensional array of integers of size 2×n2 \times n2×n, is it possible to rearrange integer ...