const 是 C++ 型別系統的基石,正確使用能顯著提升程式碼安全性、可讀性與最佳化空間。本文系統梳理 const 在變數、指標、引用、成員函數、函數參數、運算子多載等場景的語義與慣用模式。
const int i = 10; // 推薦風格:const 在型別前
int const j = 20; // 等價,但較少見
i = 15; // 編譯錯誤:不可修改
| 宣告 | 口訣 | 指標值(位址) | 指向內容 |
|---|---|---|---|
char* const p = "hello"; | const 修飾 p → 常指標 | 不可變 | 可變 |
const char* p = "hello"; | const 修飾 char* → 指向常量 | 可變 | 不可變 |
const char* const p = "hello"; | 雙重 const | 不可變 | 不可變 |
記憶技巧:const 最近修飾誰,誰就不可變。
void foo(const int& r) { /* r 不可修改 */ }
int a = 10;
foo(a); // 綁定 lvalue
foo(10); // 綁定 rvalue,延長臨時物件壽命
引用本身不可重繫結,const 僅限制透過該引用修改值。
class MyClass {
mutable int cache_; // 即使在 const 函數中也可修改
public:
int value() const { // 承諾不修改非 mutable 成員
return cache_ ? cache_ : (cache_ = compute());
}
};
const 置於參數列表後,屬於函數簽章一部分,可參與多載。mutable 允許在 const 物件中修改特定成員(如快取、鎖、統計計數器)。
class String {
char* data_;
public:
char& operator[](size_t i) { return data_[i]; } // 非 const:可修改
char operator[](size_t i) const { return data_[i]; } // const:唯讀
};
String s;
s[0] = 'A'; // 呼叫非 const 版本
char c = s[0]; // 呼叫 const 版本
標準庫容器(vector, map 等)廣泛採用此模式。
// 值傳遞:產生副本,效率低
void func1(BigObject obj);
// const 引用:無副本,且保證不修改原物件
void func2(const BigObject& obj);
原則:輸入參數優先使用 const T&;僅當需要修改呼叫端物件或參與移動語意時才用非 const 引用或值傳遞。
const 不僅是編譯期檢查工具,更是介面契約的文檔化表達。養成「預設加 const,必要時再移除」的習慣,能從語言層面杜絕大量誤修改 Bug,並協助編譯器產生更優化的機器碼。