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

本文探讨了如何通过const常量替换预处理器宏来避免编译错误和优化内存使用。介绍了enum用于类内整数常量和其隐藏地址的特性,以及inline函数如何替代宏实现更清晰的函数调用。提倡减少预处理器依赖,提高代码组织和可维护性。

一、使用const

存在问题1:宏名称可能没有进入记号表中

#define PI 3.141592654

记号名称PI也许从未被编译器看见,也许在编译器开始处理源码之前它就被预处理器替换了。

于是记号名称PI有可能没有进入记号表内,当你运用次常量但获得一个编译错误信息是,这个错误信息也许会提示3.141592654,而不是PI,对于不熟悉这个宏定义的人来说,会因为对它来自何处毫无概念而增加排错的时间;

解决方案:使用常量(const)替换宏(#define)

const double PI = 3.141592654
  • 作为一个语言常量,PI肯定会被编译器看到,所以当然会进入记号表内,也就不会存在上述问题;
  • 此外对于浮点常量而言,使用常量可能比使用#define导致较小量的码,因为预处理器会盲目的将宏名称PI替换为3.141592654,从而导致目标码中出现多份3.141592654,若改用常量PI则绝不会出现这样的情况;

注意

  • 当使用常量替换#define时,由于常量定义式通常被放在头文件内,因此有必要将指针声明为const;例如若要定义一个常量的char* name字符串,必须写const两次:const char* const name = "Zhang San";;推荐使用std::string:const std::string name ("Zhang San");
  • class专属常量,为了将常量的作用域限制于class内,你必须让它成为class的一个成员;而为确保此常量至多只有一份实体,你必须让它成为一个static成员;
class GamePlayer {
private:
	static const int NumTurns = 5;	//常量声明式
	int scores[NumTurns];			//使用该常量
}

通常C++要求你对所使用的任何东西提供一个定义式,但如果它是个class专属常量,又是static且为整数类型,则需特殊处理。只要不取它们的地址,你可以声明并使用它们而无须提供定义式。但如果你取某个class专属常量的地址,或纵使你不取地址而你的编译器却坚持要看到一个定义式,你就必须另外提供定义式:const int GamePlayer::NumTurns;(声明时获得初值,定义时不可以再设初值,旧式编译器不支持声明时赋初值,必须在定义式赋初值)

  • #define无法创建一个class专属常量,也不能够提供任何封装性,因为#define并不重视作用域;

二、使用enum

存在问题:当你在class编译器件需要一个class常量值,例如上述的数组长度,此时万一你的编译器不允许static整数型class常量 完成 in classs初值设定

解决办法:可改用所谓的“the enum hack”补偿做法,其理论基础是:一个属于枚举类型的数值可权充int被使用

class GamePlayer {
private:
	enum{NumTurns = 5};				//令NumTurns成为5的一个记号名称
	int scores[NumTurns];			//使用该常量
}

注意

  • enum hack的行为某方面说比较像#define而不是const,有时候这正是我们想要的。例如取一个const的地址是合法的,但取一个enum的地址就不合法,而取一个#define的地址通常也不合法;
  • 如果你不想让别人获得一个pointer或reference指向你的某个整数常量,enum可以帮助你实现这个约束
  • 此外虽然优秀的编译器不会为“整数型const对象”设定另外的存储空间(除非你创建一个pointer或reference指向该对象),不够优秀的编译器却可能如此,enum和#define一样,绝不会导致非必要的内存分配;

三、使用inline

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

这种函数式的宏有太多的缺点,光是想到它们就让人痛苦不堪。

解决方案

template<typename T>
inline void callWithMax(const T& a, const T& b)
{
	f(a > b ? a : b);
}

总结

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

目前还不到预处理全面隐退的时候,但也应该尽量减少使用它的频率!

  • 对于单纯常量,最好以const对象或enum替换#define;
  • 对于形似函数的宏,最好利好inline函数替换#define;
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

贝勒里恩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值