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;
}

const常量替代#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;
}

指針常量
常量指針可以改變地址內的值,但不可以改變指針指向

/*****************************************
 * 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 hackenum 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();
}

inline函數

參考文獻

  1. Scott Meyers著,侯捷譯. Effective C++中文版. 電子工業出版社. 2012.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章