在 C++ 類別設計中,若希望特定資料成員或成員函數不可被修改,const 關鍵字是不可或缺的工具。它可修飾成員變數、成員函數乃至整個物件,提供編譯期的安全保障。本文將系統性探討 const 在類別中的三大核心應用場景。
const 成員變數的宣告語法與一般 const 變數相同,僅需在型別前加上關鍵字。關鍵差別在於初始化方式:唯有透過建構函數的參數初始化串列 才能賦值,因為 const 成員不可在建構函數主體內透過指派運算子初始化。
class Student {
public:
Student(const char* name, int age, float score);
private:
const char* m_name; // const 成員變數
int m_age;
float m_score;
};
// 必須使用初始化串列
Student::Student(const char* name, int age, float score)
: m_name(name), m_age(age), m_score(score) { }
若嘗試在建構函數主體內賦值(m_name = name;),編譯器將報錯。這機制確保了 const 成員自物件出生起即擁有確定值,且終生不可更改。
被 const 修飾的成員函數稱為「常成員函數」。其核心規則:可讀取任意成員變數,但不可修改非 mutable 成員。這為呼叫端提供強烈語義保證——呼叫此函數不會改變物件可觀測狀態。
宣告與定義處皆須在參數列表後加上 const:
class Student {
public:
char* getName() const; // 宣告
int getAge() const;
float getScore() const;
};
// 定義時同樣需要 const
char* Student::getName() const { return m_name; }
int Student::getAge() const { return m_age; }
float Student::getScore() const { return m_score; }
常見錯誤:僅在宣告或定義單處加 const 會導致函數原型不匹配,因為 char* getName() const 與 char* getName() 是兩個不同簽章。
凡「唯讀」操作(getter、查詢、顯示等)皆應標記 const。這不僅是防呆,更讓介面語義清晰:呼叫端一眼即知該操作安全無副作用。
以 const 修飾物件(或指向物件的指標),得到「常物件」。其核心限制:常物件僅能呼叫 const 成員函數、存取 const 成員變數。編譯器假設非 const 成員可能修改資料,故禁止常物件存取。
const Student stu("小明", 15, 90.6); // 常物件
Student const stu2("李華", 16, 85.0); // 等效寫法
const Student* pStu = new Student("王五", 17, 88.5); // 常物件指標
int main() {
const Student stu("小明", 15, 90.6);
// stu.show(); // 錯誤:show() 非 const
cout << stu.getName() << " 年齡 " << stu.getAge() << " 成績 " << stu.getScore() << endl;
const Student* pStu = new Student("李磊", 16, 80.5);
// pStu->show(); // 錯誤
cout << pStu->getName() << " 年齡 " << pStu->getAge() << " 成績 " << pStu->getScore() << endl;
delete pStu;
return 0;
}
若 show() 亦標記 const,常物件即可呼叫。良好的實踐是:凡不修改狀態的公開介面,一律加 const。
極少數情況下,const 成員函數確需修改某些不影響物件「邏輯狀態」的資料(如快取、鎖、統計計數器)。此時可將該成員標記 mutable:
class Cache {
public:
int getValue() const {
if (!m_cached) { m_value = compute(); m_cached = true; }
return m_value;
}
private:
mutable int m_value;
mutable bool m_cached = false;
};
mutable 打破了位元常態,保留了邏輯常態,屬進階技巧,慎用。
const,承諾不修改非 mutable 成員,強化介面契約。const,除非確有修改需求。善用 const 能在編譯期捕捉大量邏輯錯誤,是 C++ 型別系統賦予開發者的強大防禦機制,請養成「預設加 const,非必要不移除」的習慣。