C++ 繼承了 C 語言的指針機制,並引入引用作為一種新的對象訪問方式。理解三種訪問模式的差異,是掌握 C++ 參數傳遞與資源管理的基石:
| 訪問方式 | 語法 | 優點 | 缺點 | 典型場景 |
|---|---|---|---|---|
| 名稱直接訪問 | obj.method() | 直觀、無額外開銷 | 作用域受限,跨函數需傳遞 | 局部變量、成員函數內部 |
| 指針間接訪問 | ptr->method() | 靈活、可空、支援多態、跨作用域 | 語義模糊、易產生懸垂指針、需手動管理 | 動態分配、多態、可選參數、C API 交互 |
| 引用訪問 | ref.method() | 語法如名稱、語義如指針、不可空、不可重綁定、編譯器輔助安全 | 隱藏間接性、生命週期綁定風險 | 函數參數/返回值首選、運算符重載、範圍-based for |
Type& ref = obj; 無默認構造,不可為空。const 資格影響綁定(const T& 可綁定臨時對象/字面量/不同但可轉換類型)。T&& + & → &;T&& + && → &&(C++11 通用引用基石)。
// 輸入參數:避免大對象拷貝
void process(const BigObject& input);
// 輸出/輸入輸出參數:替代指針,語義更清晰
void divide(int a, int b, int& quotient, int& remainder);
// 鏈式調用返回 *this
class Builder {
Builder& setName(string n) { name_ = std::move(n); return *this; }
};
// 正確:返回靜態/全局/成員對象引用
const Config& getGlobalConfig() { static Config cfg; return cfg; }
// 正確:運算符重載返回左值引用
T& operator[](size_t i) { return data_[i]; }
// 危險:返回局部變量引用 → 懸垂引用 → UB
int& bad() { int x = 42; return x; } // 編譯器警告!
函數在內存中佔據代碼段,其入口地址即函數指針。C++ 規定函數名可隱式轉換為函數指針。
// 基本形式:返回類型 (*指針名)(參數列表)
int (*cmp)(const void*, const void*); // 指向比較函數的指針
// 類型別名簡化(C++11 using 推薦)
using CompareFn = int(*)(const void*, const void*);
using MemFn = void (MyClass::*)(int, double); // 成員函數指針
int ascending(const void* a, const void* b) { ... }
CompareFn fn = ascending; // 隱式取址
CompareFn fn2 = &ascending; // 顯式取址,等效
// 調用:隱式解引用
fn(&x, &y);
// 顯式解引用(等效)
(*fn)(&x, &y);
qsort、事件循環、信號處理、異步完成通知。dlsym/GetProcAddress 獲取插件入口函數。std::invoke (C++17) / std::mem_fn 統一調用語法。| 場景 | 傳統函數指針 | 現代首選 |
|---|---|---|
| 泛型可調用對象 | 受限於固定簽名 | std::function<R(Args...)>、模板參數、Lambda |
| 性能關鍵回調 | 間接調用、難內聯 | 模板參數化、auto Lambda、std::function_ref (C++26) |
| 成員函數綁定 | 語法複雜 (obj.*pmf)(args) | std::bind/Lambda 捕獲 this/std::mem_fn |
const T&,需修改用 T&,小型可拷貝類型(int, pair<int,int>, std::string_view)按值傳遞。std::function 表達可調用概念。using 別名 簡化複雜函數指針類型,提升可讀性。