天天看點

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.

繼續閱讀