首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> C++ 入門

C++ const 關鍵字完全指南:從參數到成員函數的最佳實踐

     編輯:C++ 入門

核心哲學

const 意為「恆定不變」。被修飾的實體受編譯器強制保護,任何嘗試修改的操作都將導致編譯錯誤。良好的 const 使用能顯著提高代碼健壯性、可讀性並啟用編譯器優化。原則:Use const whenever possible。

一、修飾函數參數

1.1 指針/引用傳遞的輸入參數


// 良好:防止函數內部意外修改源數據
void StringCopy(char* dest, const char* src); 
void processData(const std::vector<int>& data); // 引用傳遞避免拷貝

規則:輸出參數(需修改)不可加 const,否則失去輸出能力。

1.2 值傳遞參數


// 不推薦:值傳遞已複製副本,const 無意義且誤導調用者
void func1(int x);          // 正確
void func1(const int x);    // 冗餘

// 非內部類型:值傳遞觸發拷貝構造,效率低
void func2(A a);            // 低效:構造臨時對象

// 推薦:const 引用傳遞,避免拷貝且語義明確
void func2(const A& a);     // 高效且安全

內部類型(int, float, 指針等)值傳遞極快,無需改為 const T&,反而降低可讀性。

1.3 參數修飾總結表

參數類型輸入參數輸出參數輸入輸出參數
內部類型 (int, float...)T (值傳遞)T* / T&T&
自定義類型 (class/struct)const T&T* / T&T&
指針類型const T*T** / T*&T*&

二、修飾函數返回值

2.1 指針/引用返回


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 異常鏈式

2.2 值返回


// 無意義:返回臨時對象副本,調用端無法修改原對象
int getInt();           // 正確
const int getInt();     // 冗餘,C++17 起甚至被忽略

// 自定義類型值返回:C++17 RVO/NRVO 消除拷貝,const 無益
A getA();               // 正確
const A getA();         // 阻礙移動語義 (C++11),不推薦

三、const 成員函數

3.1 語法與語義


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++ 為了不破壞現有語法而做的妥協設計。

3.2 核心規則

  1. const 對象只能調用 const 成員函數;非 const 對象可調用所有成員函數。
  2. const 成員函數不可修改對象的非 mutable 數據成員,無論對象本身是否 const。
  3. 編譯期檢查:以「是否修改成員數據」為依據,而非運行時對象的 const 性質。
  4. mutable 成員:在 const 函數中也可修改,適用於快取、鎖、引用計數等邏輯可變但語義不可變的場景。

3.3 重載區分


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 版本
}

四、進階場景

4.1 const 指針 vs 指針常量


int val = 10;
const int* p1 = &val;    // 指向常量的指針:不可通過 p1 修改 val
int* const p2 = &val;    // 常量指針:p2 本身不可修改指向
const int* const p3 = &val; // 兩者皆不可修改

口訣:const 在 * 左側修飾指向內容,右側修飾指針本身。

4.2 模板與 const 傳遞


template <typename T>
void func(const T& param); // 通用輸入參數模式

// 完美轉發場景需區分 const 性質
template <typename T>
void wrapper(T&& param) {
    func(std::forward<T>(param)); // 保持左值/右值、const/volatile 屬性
}

4.3 constexpr 與 constexpr 函數


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 起允許較複雜邏輯。

五、最佳實踐檢查清單

  • [ ] 所有不修改參數的引用/指針參數加 const
  • [ ] 所有不修改成員的成員函數加 const
  • [ ] 所有不需修改的局部變量、指針、引用加 const
  • [ ] 單例、全局配置、不可變對象使用 const 或 constexpr
  • [ ] 避免 const_cast 移除常量性,除非對接無 const 正確性的舊式 API
  • [ ] 代碼審查時檢查 const 正確性,作為代碼質量指標

總結

const 不僅是關鍵字,更是設計契約。它將「不可變性」從文檔提升為編譯器強制執行的語言機制,是 C++ 類型系統安全性的基石。養成「默認 const,按需移除」的習慣,代碼將更健壯、更易維護、更利於優化。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved