Effective C++ 学习笔记 条款02 尽量以const、enum、inline替换#define
宁可以编译器替换预处理器。因为或许#define不被视为语言的一部分,当你:
#define ASPECT_RATIO 1.653
名字ASPECT_RATIO从未被编译器看到,可能在编译器处理源码前它就被预处理器移走了,于是ASPECT_RATIO可能没进入记号表(symbol table)内,当运用此常量获得一个编译错误时,会带来困惑,因为错误信息可能会提到1.653而不是ASPECT_RATIO。当这个名字被定义在并非你写的头文件内时,会因为追踪它而浪费很多时间。
解决方法:
const double AspectRatio = 1.653; // 使用常量替换宏,大写名常用于宏,因此改变写法
此时名称会进入记号表。此外,对于浮点常量,常量可能比宏更省空间,因为预处理器盲目地将宏名称替换为值,可能导致目标码出现多份值,而常量只会出现一份值。
常量替换宏时,如果常量定义的是一个指针,应把指针定义为const的,以便使该指针永远指向某对象。
书中写道:
class GamePlayer {
private:
static const int NUM_TURNS = 5; // 常量声明式,而非定义
int scores[NUM_TURNS]; // use of constant
};
const int GamePlayer::NUM_TURNS; // 定义式,放在实现文件中,由于类内已赋初值,此处不用赋初值
// 书上说此处定义作用为,要取地址值时,必须有定义式
我测试时,就算没有类外定义static常量,也能取到该常量的地址。可能是编译器优化或新版本C++特性,最好加上。
我们无法使用#define创建一个class专属常量,#define不重视作用域,只要被定义,就在编译过程中有效(除非#undef),它不能提供封装性,即没有private #define。
比较旧的编译器可能不支持static成员在类内获得初值。in-class初值设定也只能对整型常量进行。此时我们可以在类外定义static值。
但当class编译器需要一个类内常量,如创建一个数组时,可用enum,enum类型的值可当做整型使用:
class A {
private:
enum { NumTurns = 5 };
int scores[NumTurns];
}
enum中的枚举项不能取地址,#define的宏也不能取地址。但enum类型的值可以取地址:
enum test { a = 5 };
test *p = &a; // 错误
test t = a;
test* pEnum = &t;
cout << *pEnum << endl; // 输出5
如果你不想让别人获得一个pointer或reference指向你的某个整数常量,enum可以实现这个约束。
#define可以实现宏函数,但它不会招致函数调用带来的开销,如:
#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b)) // f是函数,选较大的一个数传入函数
要为宏中每个实参加上小括号,否则由于运算符的优先级,会导致意想不到的结果。我们直接将以上宏函数改写为inline模板函数,就不会出现由于运算符优先级产生的未知结果了。但仍然会出现其他未知结果,如:
CALL_WITH_MAX(a++, b); // 当a>b时,a自增两次,否则自增一次
因此以上宏函数最好使用templete inline函数代替。
预处理器除#define外还有更多作用,如#ifdef可以控制编译、#include仍是必需品,但应该尽量少用它预处理器。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· 开发者必知的日志记录最佳实践
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)