「Effective C++」条款02:尽量以const,enum,inline替换#define

1.关于 #define 的简介

​ 需要注意的是#define PI 3.14159发生作用在预处理阶段,在编译阶段之前,也就是说在预处理阶段,预处理器会进行文本替换 ,把所有非字符串形式的PI 都替换为 3.14159 。 常见的关于 #define 的用法,以下是使用 #define 定义一个常量或者函数:

·定义常量: #define PI 3.14159
·定义函数: #define Sum(a,b) a*b*a*b*a*b*a*a*b

2. #define 的优缺点:

但是,使用以上的两种常用的方式,会有相应的缺点和优点:

关于:#define PI 3.14159

优点:

  • 不需用在所有需用使用到常量 3.14159 的地方书写数字,避免粗心输入错误的问题,可以使用宏更好的见名知意。

缺点:

  • 正如上面描述,因为宏替换发生在预处理阶段,是预处理器在负责,所以编译器看不到PI,所以如果常量3.14159 在编译阶段报错,报的错会提示3.14159的错误,而不是PI的问题,从而你无法定位具体错误在哪里,得思考3.14159是什么,再极端点,这个PI定义在一个不是你写的头文件里面,那就更加麻烦了。
  • 无法提供作用域(除非使用#undef )。
关于: #define Sum(a,b) a*b*a*b*a*b*a*a*b
  • 优点:
    • 节约函数调用的时间,所有使用Sum函数的地方,都进行了宏替换
    • 使用方便
  • 缺点:
    • 单纯的文本替换,在所有使用宏的地方都会出现的a*b*a*b*a*b*a*a*b副本,假如函数体很长,十分不可行
    • 实参括号容易出错
    • 无法提供作用域(除非使用#undef)

3.关于#define PI 3.14159 缺点的处理方式

#define PI 3.14159

建议替换为如下形式:

const double pi = 3.14159;   //大写是宏的命名方式

或:

class Stu
{
	private:
	static const double pi = 3.14159;     //这种方式把pi的作用域限制在了class内,且pi只有一份实体
};

或:

class Stu
{
	private:
	enum{Num = 3};    //这种方式理论基础:"一个属于枚举类型的数值,可权充ints被使用"
					  //还有个好处,这种方式可以让你避免Num被取地址
	int size[Num];
};
4.关于#define Sum(a,b) a*b*a*b*a*b*a*a*b 缺点的处理方式
#define Sum(a,b) a*b*a*b*a*b*a*a*b

建议替换为内联函数:

inline int Sum(int a,int b)
{
	return a*b*a*b*a*b*a*a*b;   //使用inline函数提高效率
}

或使用函数模板:

template<typename T>
inline T Sum(const T &a,const T &b)
{
	return a*b*a*b*a*b*a*a*b;    //使用函数模板来满足宏的类型匹配问题 
}
5.const为什么不会导致重复定义问题?

当在C++中定义全局变量时,如果多个源文件包含了同一个头文件,并且该头文件中定义了全局变量,将会导致重复定义的错误。然而,对于 const 修饰的全局变量,它们在默认情况下具有内部链接(internal linkage),因此不会导致重复定义的错误。

内部链接意味着 const 变量只在定义它的源文件中可见,其他源文件无法访问它。当多个源文件包含同一个头文件时,每个源文件会独立拥有自己的 const 变量副本,而这些副本在不同的源文件中是相互独立的。

这种行为是因为编译器将具有 const 修饰的全局变量视为只读常量,因此对于每个源文件来说,它们并不需要在链接阶段合并为一个定义。相反,编译器将在每个源文件中生成自己的 const 变量,这些变量在链接时不会发生冲突。

需要注意的是,如果在全局变量定义时使用了 extern 关键字,它将不再具有内部链接,并且会导致重复定义的错误。例如:

// header.h
extern const int a;

// source1.cpp
#include "header.h"
const int a = 10;

// source2.cpp
#include "header.h"
const int a = 20;  // 重复定义错误!

在上述示例中,使用 extern 关键字声明了 a,表示它在其他源文件中定义。然而,由于头文件中的 a 并没有具体的定义,因此每个源文件会生成自己的 a 定义,最终导致重复定义的错误。

综上所述,对于使用 const 修饰的全局变量,默认情况下具有内部链接,每个源文件都会生成自己的副本,不会导致重复定义的错误。而对于带有 extern 关键字的全局变量,需要在某个源文件中进行实际的定义,然后在其他源文件中进行声明以避免重复定义的错误。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值