您的位置:首页 > 编程语言 > C语言/C++

C++程序中尽量避免#define

2015-09-12 13:56 537 查看

使用
const
,
enum
替换
#define
定义常量

C
语言中常用
#define
来定义具有某种特殊意义的常量。但是,使用
#define
宏定义定义的符号会在编译前被替换掉,当因为该宏定义出现问题时,在错误信息中无法获得有关该宏的任何提示,这对错误的发现带来困难,,尽管可以通过查看预编译输出的方式尝试定位问题。同时预处理也会在程序中产生多份副本,造成代码量较大。

为了解决这些问题,可以使用
const
常量替代宏定义的常量,这样定义的常量会被加入记号表内,而被编译器看到,同时所有使用该常量的地方都是对同一个常量的引用,不会出现多份的情况。

/****************************************
* const_value.cpp                      *
*                                      *
* C++高效原则之一用const代替#define    *
****************************************/

#include <iostream>

int main()
{
const int PRICE = 10.0;

std::cout<<"输入数量: "<<std::endl;
int x;
std::cin>>x;

std::cout<<"总价为: "<<PRICE * x<<std::endl;

return 0;
}




在这个例子中,发现一个问题,就是
C++
cin
输入回显是要换行的,而C语言中的
scanf
却不用。上例中,前一个是
C
程序,使用
printf
输出,
scanf
输入回显不换行,第二个是
C++
程序,使用
cout
输出,
cin
输入。

在使用
const
与指针结合时,有两种不同的形式,一种是指针常量,使用类似
const char *
的定义,说明该指针指向的内存地址里的内容不可改变,另一种是常量指针,使用类似
char* const
定义,说明指针本身是个常量,它不能指向当前所指地址外的其他地址。

指针常量可以改变指向的地址,但不可以通过指针改变地址内的值。

/****************************************
* pointer_const.cpp                    *
*                                      *
* C++指向常量的指针(指针常量)            *
****************************************/

#include <iostream>

int main()
{
int a = 10;
int b = 20;
const int *p = &a;
p = &b;

*p = 30;

return 0;
}




常量指针可以改变地址内的值,但不可以改变指针指向

/*****************************************
* const_pointer.cpp                     *
*                                       *
* 常量指针                              *
*****************************************/

#include <iostream>

int main()
{
int a = 20;
int* const p = &a;
*p = 30;

int b = 50;
p = &b;

return 0;
}




const
类型常量可以用以定义类常量,类常量是类中的一个
static const
成员,它的作用域为类内,且在各个对象中共享一份。当类常量是基本类型时,只要不取它们的地址,可以声明并使用它们而无需定义式。如果需要取它们的地址,或者编译器不支持以上原则,则需要在定义文件中额外提供类常量的定义式。如果在声明式子中已设置初值(有些编译器不支持,必须将初始化放于定义式中),则在定义式中就不能在设置初值。而在这一方面,宏定义无法来定义类常量,它缺乏作用域的限定,不具有封装性。

//-*-C++-*-

class GamePlayer
{
private:
static const int NumTurns = 5;

public:
void PrintNumTurns();
};


#include "GamePlayer.h"

#include <iostream>

void GamePlayer::PrintNumTurns()
{
std::cout<<"NumTurns = "<<NumTurns<<std::endl;
}

int main()
{
GamePlayer a;
a.PrintNumTurns();
}




若只在类中提供类常量声明式,当试图引用指针时,就会报错:

//GamePlayer.cpp
#include "GamePlayer.h"

#include <iostream>

void GamePlayer::PrintNumTurns()
{
std::cout<<"NumTurns = "<<NumTurns<<std::endl;

const int *p = &NumTurns;

std::cout<<"NumTurns = "<<*p<<std::endl;
}

int main()
{
GamePlayer a;
a.PrintNumTurns();
}




在定义文件中添加定义式即可。

//GamePlayer.cpp
#include "GamePlayer.h"

#include <iostream>

const int GamePlayer::NumTurns;

void GamePlayer::PrintNumTurns()
{
std::cout<<"NumTurns = "<<NumTurns<<std::endl;

const int *p = &NumTurns;

std::cout<<"NumTurns = "<<*p<<std::endl;
}

int main()
{
GamePlayer a;
a.PrintNumTurns();
}




当对定义的整型常量 需要某些类似宏的行为时,例如不能取地址,不会导致额外的存储空间,可以使用
enum hack
enum hack
利用枚举类型的数值来充当整型使用。

//GamePlayer.h
//-*-C++-*-

class GamePlayer
{
private:
enum {NumTurns = 5};

public:
void PrintNumTurns();
};


//GamePlayer.cpp
#include "GamePlayer.h" #include <iostream> void GamePlayer::PrintNumTurns() { std::cout<<"NumTurns = "<<NumTurns<<std::endl; } int main() { GamePlayer a; a.PrintNumTurns(); }




使用inline函数替换形似函数的宏

C
语言中常定义类似于函数的宏,尽管这样的宏有不带来函数调用的额外开销,但这样定义的宏很容易出现问题。在
C++
中,可以使用
template inline
函数获得宏带来的效率以及一般函数的所有预料行为和类型安全性。

//-*-C++-*-
//GamePlayer.h
#define MAX(a, b) a > b ? a : b

class GamePlayer
{
private:
template<typename T>
inline T max(const T& a, const T& b);
public:
void PrintMaxUsingMacro();
void PrintMaxUsingInlineFunction();
};


//GamePlayer.cpp

#include "GamePlayer.h"

#include <iostream>

template<typename T>
T GamePlayer::max(const T& a, const T& b)
{
return a > b ? a : b;
}

void GamePlayer::PrintMaxUsingMacro()
{
int a = 20;
int b = 30;
std::cout<<"a和b中最大的值是"<<(MAX(a,b))<<std::endl;
}

void GamePlayer::PrintMaxUsingInlineFunction()
{
int a = 20;
int b = 30;
std::cout<<"a和b中最大的值是"<<max(a,b)<<std::endl;
}

int main()
{
GamePlayer a;
a.PrintMaxUsingMacro();
a.PrintMaxUsingInlineFunction();
}




参考文献

Scott Meyers著,侯捷译. Effective C++中文版. 电子工业出版社. 2012.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: