在 C++ 開發中,預處理器巨集(#define)常被用來定義常量,但這種做法存在型別不安全、難以除錯、不尊重作用域等缺點。現代 C++ 建議改用編譯器常量(const、constexpr、enum、inline 函數)來取代預處理常量,以提升程式碼品質與維護性。
const 取代 #define對於單純的常數值,直接使用 const 變數即可。編譯器會進行型別檢查,且符合作用域規則。
// 不推薦
#define ASPECT_RATIO 1.653
// 推薦
const double AspectRatio = 1.653;
const 成員與 enum hackconst 整數常量(C++11 前)類別內僅允許對 static const 整數型別(含 enum)進行初始化;其他型別需在類別外定義。
class GamePlayer {
private:
static const int NumTurns = 5; // 允許:整數常量
static const double MaxScore = 99.9; // 錯誤:非整數型別
};
// 類別外定義
const double GamePlayer::MaxScore = 99.9;
enum hack 技巧若編譯器不支援類內初始化,可利用 enum 達到相同效果,且可用於陣列大小宣告。
class GamePlayer {
private:
enum { NumTurns = 5 }; // 編譯期常量,可作為陣列大小
int scores[NumTurns];
};
constexpr 與 static constexpr現代 C++ 推薦使用 constexpr,保證編譯期運算,支援所有字面型別。
class GamePlayer {
static constexpr int NumTurns = 5;
static constexpr double MaxScore = 99.9;
};
inline 函數預處理器巨集函數缺乏型別安全、引數副作用風險大。改用模板內聯函數可獲得同樣效率並享有型別檢查。
// 巨集版本(危險)
#define CALL_WITH_MAX(a, b) f((a) > (b) ? (a) : (b))
// 模板內聯版本(安全)
template
inline void callWithMax(const T& a, const T& b) {
f(a > b ? a : b);
}
/* effectivecpp.cpp
* Created on: 2013.11.13
* Author: Caroline
* Compiler: eclipse cdt ; gcc 4.7.1
*/
#include <iostream>
#include <string>
#include <array>
#include <algorithm>
using namespace std;
// 常量定義
const double AspectRatio = 1.653; // 取代 #define
// 類別內常量示範
class GamePlayer {
static constexpr int NumTurns = 5;
static constexpr double MaxScore = 99.9;
int scores[NumTurns]; // 合法:constexpr 可作為陣列大小
};
// 模板內聯函數取代巨集
template
inline const T& max(const T& a, const T& b) {
return a > b ? a : b;
}
int main() {
cout << "AspectRatio: " << AspectRatio << endl;
cout << "Max(3, 5): " << max(3, 5) << endl;
return 0;
}
const / constexpr 變數static constexpr 或 enumstatic constexpr (C++11) 或類外定義inline 函數善用編譯器常量不僅能消除巨集的缺陷,更能讓編譯器協助發現錯誤,生成更安全、高效、可維護的 C++ 程式碼。