在 C++ 抽象機中:
int 用補碼,float 用 IEEE-754)。* (指針)、& (引用)、[] (數組)、() (函數)、::* (成員指針)、const 等。T* 表示:「將一個數值按無符號整數編碼 (機器字寬),視為內存地址;解引用時按 T 的規則解釋該地址起始的位模式。」
*p (解引用) = **類型轉換**:將 T* 型值轉為 T 的**地址類型**值 (地址不變,類型變)。&x (取址) = **類型轉換**:將 T 的**地址類型**值轉為 T* 型值。&*p == p、**不訪問內存**,純編譯期類型轉換。p + n = 地址值 + n * sizeof(T) (按元素步進)。a[n] ≡ *(a + n) ≡ *(n + a) ≡ n[a]。T[N] 隱式轉換為 T* (退化為首元素地址),**但丟失長度信息**。sizeof(T[N]) == N*sizeof(T),sizeof(T*) == 機器字寬。int a = 10;
int *p1 = &a; // int*
int **p2 = &p1; // int**
int ***p3 = &p2; // int***
// ***p3 === a
// 每級解引用剝離一層 *,地址值不變,類型逐級變化。
類型修飾符 () 表示「可調用實體」,參數列表與返回類型構成函數類型。
// 普通函數指針
int (*pf)(double, char); // 指向 int(double,char) 的指針
// 成員函數指針 (需類作用域)
struct A { void foo(int); };
void (A::*pmf)(int) = &A::foo;
(A.*pmf)(42); // 物件調用
(pA->*pmf)(42); // 指針調用
**成員函數指針非單純地址**,可能包含 this 偏移、虛表索引等 (實現定義),**大小不固定**,不可轉換為 void*。
int (*pa)[10]; // 指向 int[10] 的指針 (數組指針)
int *ap[10]; // 10 個 int* 的數組 (指針數組)
// 讀法:從變量名出發,先看右邊 []/(),再看左邊 *。
struct S { int x; double y; };
int S::*pmx = &S::x; // 偏移量編碼
double S::*pmy = &S::y;
S obj; S* p = &obj;
obj.*pmx = 1; // 直接訪問
p->*pmx = 2; // 通過指針訪問
// 多繼承/虛繼承下可能包含多個偏移量 + vbptr 索引,大小 > 機器字寬。
| 誤區 | 真相 |
|---|---|
| 指針就是地址 | 指針 = 地址值 + 類型信息 (編譯期);void* 只有地址值,無類型信息 |
| *p 訪問內存 | *p 是類型轉換,**編譯期**動作;實際內存訪問由後續賦值/讀取指令觸發 |
| 數組就是指針 | 數組有長度、占用連續存儲、sizeof 為總大小;退化為指針時丟失長度 |
| 函數指針可轉 void* | 標準禁止;實踐中常違規但不可移植 (如 dlsym 返回 void*) |
| 成員指針 = 偏移量 | 單繼承非虛基類才是純偏移;多繼承/虛繼承包含額外調度信息 |
std::unique_ptr/shared_ptr 管理生命週期。T* (可空) / T& (非空) / std::span (數組視圖) / std::function (可調用物)。std::invoke/std::mem_fn 實現泛化調用。指針是 C++ 類型系統中最強大、最危險的修飾符。理解其「類型轉換本質、地址運算規則、退化行為、成員指針特殊編碼」,才能寫出正確、高效、可維護的現代 C++ 代碼。