const 意為「恆定不變」。被修飾的實體受編譯器強制保護,任何嘗試修改的操作都將導致編譯錯誤。良好的 const 使用能顯著提高代碼健壯性、可讀性並啟用編譯器優化。原則:Use const whenever possible。
// 良好:防止函數內部意外修改源數據
void StringCopy(char* dest, const char* src);
void processData(const std::vector<int>& data); // 引用傳遞避免拷貝
規則:輸出參數(需修改)不可加 const,否則失去輸出能力。
// 不推薦:值傳遞已複製副本,const 無意義且誤導調用者
void func1(int x); // 正確
void func1(const int x); // 冗餘
// 非內部類型:值傳遞觸發拷貝構造,效率低
void func2(A a); // 低效:構造臨時對象
// 推薦:const 引用傳遞,避免拷貝且語義明確
void func2(const A& a); // 高效且安全
內部類型(int, float, 指針等)值傳遞極快,無需改為 const T&,反而降低可讀性。
| 參數類型 | 輸入參數 | 輸出參數 | 輸入輸出參數 |
|---|---|---|---|
| 內部類型 (int, float...) | T (值傳遞) | T* / T& | T& |
| 自定義類型 (class/struct) | const T& | T* / T& | T& |
| 指針類型 | const T* | T** / T*& | T*& |
const char* getString(); // 返回內容不可修改
// 正確使用:
const char* p = getString();
// 錯誤:char* p = getString(); // 捨棄 const 資格
// 引用返回:鏈式賦值場景
class A {
A& operator=(const A& other); // 返回 *this 支援 a=b=c
};
const A& operator=(const A& other); // 返回 const 禁止 (a=b)=c 異常鏈式
// 無意義:返回臨時對象副本,調用端無法修改原對象
int getInt(); // 正確
const int getInt(); // 冗餘,C++17 起甚至被忽略
// 自定義類型值返回:C++17 RVO/NRVO 消除拷貝,const 無益
A getA(); // 正確
const A getA(); // 阻礙移動語義 (C++11),不推薦
class Stack {
int count_;
int data_[100];
public:
int getCount() const; // 承諾不修改成員變量
void push(int v); // 非 const,修改 count_ 和 data_
};
int Stack::getCount() const {
// ++count_; // 編譯錯誤:嘗試修改成員
// push(0); // 編譯錯誤:調用非 const 成員函數
return count_; // 唯讀訪問合法
}
const 放在參數列表後、函數體前,是 C++ 為了不破壞現有語法而做的妥協設計。
mutable 數據成員,無論對象本身是否 const。mutable 成員:在 const 函數中也可修改,適用於快取、鎖、引用計數等邏輯可變但語義不可變的場景。
class TextBlock {
std::string text_;
public:
// 非 const 版本:允許修改返回的字符引用
char& operator[](std::size_t pos) { return text_[pos]; }
// const 版本:返回 const 引用,防止修改
const char& operator[](std::size_t pos) const { return text_[pos]; }
};
void print(const TextBlock& ctb) {
std::cout << ctb[0]; // 調用 const 版本
}
void modify(TextBlock& tb) {
tb[0] = 'X'; // 調用非 const 版本
}
int val = 10;
const int* p1 = &val; // 指向常量的指針:不可通過 p1 修改 val
int* const p2 = &val; // 常量指針:p2 本身不可修改指向
const int* const p3 = &val; // 兩者皆不可修改
口訣:const 在 * 左側修飾指向內容,右側修飾指針本身。
template <typename T>
void func(const T& param); // 通用輸入參數模式
// 完美轉發場景需區分 const 性質
template <typename T>
void wrapper(T&& param) {
func(std::forward<T>(param)); // 保持左值/右值、const/volatile 屬性
}
constexpr int factorial(int n) {
return n <= 1 ? 1 : n * factorial(n-1);
}
constexpr int val = factorial(5); // 編譯期計算
static_assert(val == 120);
constexpr 隱含 const,但更強:要求編譯期可計算,C++14 起允許較複雜邏輯。
constconstconstconst 或 constexprconst_cast 移除常量性,除非對接無 const 正確性的舊式 APIconst 不僅是關鍵字,更是設計契約。它將「不可變性」從文檔提升為編譯器強制執行的語言機制,是 C++ 類型系統安全性的基石。養成「默認 const,按需移除」的習慣,代碼將更健壯、更易維護、更利於優化。