天天看点

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

使用

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++程序中尽量避免#define

在这个例子中,发现一个问题,就是

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;
}
           
C++程序中尽量避免#define

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

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

#include <iostream>

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

  int b = 50;
  p = &b;

  return 0;
}
           
C++程序中尽量避免#define

const

类型常量可以用以定义类常量,类常量是类中的一个

static const

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

//-*-C++-*-

class GamePlayer
{
private:
  static const int NumTurns = ;

public:
  void PrintNumTurns();
};
           
#include "GamePlayer.h"

#include <iostream>

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

int main()
{
  GamePlayer a;
  a.PrintNumTurns();
}
           
C++程序中尽量避免#define

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

//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();
}
           
C++程序中尽量避免#define

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

//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();
}
           
C++程序中尽量避免#define

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

enum hack

enum hack

利用枚举类型的数值来充当整型使用。

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

class GamePlayer
{
private:
  enum {NumTurns = };

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();
}
           
C++程序中尽量避免#define

使用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 = ;
  int b = ;
  std::cout<<"a和b中最大的值是"<<(MAX(a,b))<<std::endl;
}

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

int main()
{
  GamePlayer a;
  a.PrintMaxUsingMacro();
  a.PrintMaxUsingInlineFunction();
}
           
C++程序中尽量避免#define

参考文献

  1. Scott Meyers著,侯捷译. Effective C++中文版. 电子工业出版社. 2012.

继续阅读