使用 const
, enum
替換 #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++
中
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 = ;
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 = };
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 = ;
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();
}
參考文獻
- Scott Meyers著,侯捷譯. Effective C++中文版. 電子工業出版社. 2012.