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

C++ const 關鍵字完全指南:從基本用法到底層原理與進階技巧

     編輯:關於C語言

前言

`const` 是 C++ 型別系統的核心,遠不止「定常量」。正確使用 `const` 能讓編譯器捕獲邏輯錯誤、優化代碼、表達設計意圖、支援多執行緒安全。本文系統整理 8 大基本規則、指針/引用/成員函數/模板中的進階用法、常見誤區與最佳實踐。

一、八大基本規則速查

#規則正確示例錯誤示例
1修飾變量為唯讀,必須初始化`const int MAX = 100;``const int x; // 錯誤`
2取代 `#define`,擁有型別與作用域`const double PI = 3.14159;``#define PI 3.14159`
3跨文件共享需 `extern` 聲明,定義處初始化h: `extern const int N;`
cpp: `const int N = 10;`
h: `extern const int N = 10;`
4編譯器執行型別檢查,避免隱式縮窄`const long L = 10; char c = L; // 警告``#define L 10; char c = L; // 無警告`
5字串常量僅一份拷貝,節省記憶體`const char* s = "hello";``#define S "hello"` 每處展開一份
6可用函數返回值初始化(運行期常量)`const int sz = computeSize();`無
7可通過強制轉型修改(未定義行為,勿用)`const int i=0; *(int*)&i = 1; // UB`視為只讀優化依據
8區分「頂層 const」與「底層 const」見下節混淆導致賦值錯誤

二、指針與引用的 const 組合(核心難點)


int i = 0;
const int ci = 10;

const int *p1 = &ci;   // 底層 const:指向常量的指針,可改指向,不可改值
int *const p2 = &i;    // 頂層 const:常量指針,不可改指向,可改值
const int *const p3 = &ci; // 雙重 const

// 判斷口訣:從右向左讀
// const int *p  → "p is a pointer to const int"
// int *const p  → "p is a const pointer to int"

賦值相容性:`const int*` 可接收 `int*`(加強限制),`int*const` 不可接收 `int*`(頂層 const 不影響指向對象權限)。

三、成員函數 const 資格


class Buffer {
    char *data;
    size_t len;
public:
    // 承諾不修改對象可見狀態
    size_t size() const { return len; }
    char operator[](size_t i) const { return data[i]; } // 唯讀版本
    char& operator[](size_t i) { return data[i]; }      // 讀寫版本

    // mutable 成員可在 const 函數中修改(緩存、鎖、統計計數)
    mutable int accessCount;
    char get(size_t i) const { ++accessCount; return data[i]; }
};

規則:`const` 對象只能調用 `const` 成員函數;`const` 成員函數不可修改非 `mutable` 成員。

四、構造/析構與 const

  • 構造函數**不能**加 `const`(正在構建對象)。
  • 析構函數**不能**加 `const`(正在銷毀對象)。
  • 但可構造 `const` 對象:`const Widget w;` → 之後只能調用 `const` 方法。

五、模板與 const 傳遞


template
void func(const T& param);  // 推導 T 時保留 const 屬性

// C++17 std::as_const:將左值轉為 const 右值引用
#include <utility>
void legacyAPI(Widget&);  // 非 const 參數
legacyAPI(std::as_const(widget)); // 編譯錯誤,防止誤調

六、constexpr vs const(C++11/14/17/20)

特性constconstexpr
求值時機運行期或編譯期強制編譯期
函數不可可(C++14 放寬限制)
適用對象任何變量字面類型
用作模板參數/陣列大小不可可

**原則**:能 `constexpr` 就 `constexpr`,將計算前移編譯期。

七、常見誤區與避坑

  1. ❌ `const int* p = malloc(4);` → 應 `int* p = ...`,`const` 修飾的是指向內容,非指針本身。
  2. ❌ 返回 `const std::string&` 卻返回區域變量引用 → 懸空引用,與 `const` 無關。
  3. ❌ 以為 `const` 保證線程安全 → 僅保證「不修改」,複合操作仍需鎖/原子操作。
  4. ❌ 函數參數 `const T&` 卻在函數內 `const_cast` 修改 → 未定義行為(若實參為真 `const` 對象)。

八、最佳實踐清單

  • ✅ 所有不修改對象的成員函數加 `const`。
  • ✅ 所有輸入參數指針/引用預設加 `const`(`const T*`, `const T&`)。
  • ✅ 循環變量 `for (const auto& x : vec)`。
  • ✅ 全域/命名空間常量用 `constexpr` / `inline const` (C++17) 替代宏。
  • ✅ 返回值不加 `const`(阻礙移動語義),除非返回 `const&`。
  • ✅ 善用 `std::as_const` 獲取 `const` 視圖調用 `const` 重載。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved