欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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

程序员文章站 2024-03-23 13:54:58
...

一、用const替换#define

 
  #define 存在以下的问题:

1. 发生编译错误时,很难追踪

#define PI 3.14		

 
  如果运用了上面定义的常量时,由于在预编译时,所以用到了PI的地方全部都已经被替换掉了,若发生编译错误,错误信息只会提到3.14,而不是PI,非常的难以追踪。
  解决方法就是用常量替换#define

	const double PI = 3.14;			//则替换了#define
	const double* const PI = 3.14;	//若是使用指针需要const两次
	*PI = 3.1415926;				//这就会报错,原因条款三说明
	double i = 2.12;
	PI = &i;						//这也会报错

2.没有封装性,不能限制作用域

 
  若想创建class专属常量,无法用#define创建,因为它的作用域并没有限制,一旦宏被定义,就一直有效(除非去#undef),因此使用const常量,只要将其作用域限制于class内(即让它成为class的一个成员),而为了让它只有一份实体,让它成为一个static成员。

class GamePlayer
{
	private:
		static const int NumTurns = 5;	//静态常量声明式,所有实例共享
		static const int Num;			//静态常量声明式
		int scores[NumTurns];			//使用上面定义的常量
}
#include "gameplayer.h"

	const int GamePlayer::Num = 5;			//Num定义式,在实现文件中

 
  上面的常量NumTurns是声明式而非定义式,而对于一般的staic变量(Num),是在头文件中声明它是static,而在源文件中定义的;而对于static const变量,假如这个变量是“整数”类型:int,char,bool,那么直接就可以直接声明,而不用定义。

二、用enum代替#define

 
  在上面用作数组大小时,用const代替,若不想让别人获得一个指针或印用指向该常量时,enum就可以实现这个约束条件。

class GamePlayer
{
	private:
		enum { NumTurns = 5 };			//enum,令NumTurns成为5的一个标记
		int scores[NumTurns];
}

 
  取enum的地址是不合法的,而取const的地址确是合法的,因此认识enum是有必要的。而这也是template metaprogramming(模板元编程)的基础技术。

三、用inline代替#define

 
  当用#define实现宏时,宏看起来像函数,但不会招致函数调用带来的额外开销。

#include <iostream>
using namespace std;
#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))

int main()
{
	int a = 5, b = 0;
	CALL_WITH_MAX(a++, b);			//a累加两次
	CALL_WITH_MAX(a++, b++);		//a累加一次
	return 0;
}

 
  在上面的main函数中,宏中的两个实参较大值调用函数 f (),调用宏时,a的递增次数竟然取决于a和b的大小;并且类型是否相同,也没有检查。
  而使用template inline函数,则可以解决上述问题。

template<typename T>					
inline void callWithMax(const T& a, const T& b){
	f(a > b ? a : b);				//因为不确定a, b的类型,用模板编程
}

四、请记住

 

  • 对于单纯常量,最好以const对象或enums替换#defines。
  • 对于形似函数的宏,最好改用inline函数替换#defines。