眾所周知,參考作為函數參數可避免物件拷貝,對非內建型別效率更高,且比指標更安全、語義更清晰。但參考在同一作用域內還有哪些獨特價值?本文將探討參考作為「別名」、簡化深層資料成員存取、以及模擬 C# 風格屬性的進階技巧。
考慮巢狀迴圈計數器:
int i = 0, j = 0;
for (i = 0; i < 10; ++i)
for (j = 0; j < 10; ++j)
a[i][j] = 0;
變數 i、j 語義不明。若引入參考別名:
const int width = 10, height = 10;
int i = 0, j = 0;
int &row = i; // 行別名
int &col = j; // 列別名
for (row = 0; row < height; ++row)
for (col = 0; col < width; ++col)
a[row][col] = 0;
程式碼瞬間變得自文檔化。當必須使用第三方庫中語義不清的變數名時,此技巧尤為實用。
網路編程中常見 mbuf 這類深層巢狀結構:
struct mbuf {
struct m_hdr mhdr;
union {
struct {
struct pkthdr MH_pkthdr;
union {
struct m_ext MH_ext;
char MH_databuf[MHLEN];
} MH_dat;
} MH;
char M_databuf[MLEN];
} M_dat;
};
存取 MH_databuf 需寫 m.M_dat.MH.MH_dat.MH_databuf。傳統做法用巨集壓扁存取路徑,但巨集汙染全域命名空間。參考提供類型安全的替代方案:
mbuf m;
m_ext &ext = m.M_dat.MH.MH_dat.MH_ext; // 建立別名
ext.some_field = value; // 直接操作
更進一步,配合 const 參考可防止誤寫:
const m_ext &ext = m.M_dat.MH.MH_dat.MH_ext; // 唯讀檢視
在面向物件設計中,若 Get() 回傳參考,外部同樣可定義參考簡化連續存取:
auto &deep = obj.GetDeepMember(); // 避免 obj.GetDeepMember().GetSubMember() 的冗長
C# 的 property 語法允許 a.x = 8; int b = a.x; 形式存取。C++ 可用公開參考成員模擬:
class CA {
int m_i;
public:
int &i; // 讀寫屬性
const int &c_i; // 唯讀屬性
CA() : i(m_i), c_i(m_i) {}
};
使用方式:
CA a;
a.i = 42; // 寫入
int v = a.i; // 讀取
int cv = a.c_i; // 唯讀
缺點:早期編譯器(如 VC6)將參考實現為指標,導致類別體積膨脹。現代編譯器已優化此問題,但仍需注意二進位相容性。
參考作為「別名」機制,除函數參數外,在以下場景極具價值:
善用參考的這些特性,能讓 C++ 程式碼更具表達力與維護性。