C++的類成員指標是一種奇葩的指標。
假設現在我們要表示一個三維的點,現在有兩種定義方式:
struct point1{
int x, y, z;
};
struct point2{
int c[3];
};
第一種的優點是更直觀,但第二種可以方便的用for遍歷三個屬性。最終我選擇了第一種,但是我還想弄一個遍歷功能怎麼辦?這個時候類成員指標就排上用場了,我們可以建立一個“指向point中具體成員的指標”。
int A:: *member = &A::x;
讓member指標指向A中的成員x,且型別是int,此時我們就可以通過member來訪問x:
point1 tmp{4, 5, 6};
cout << tmp.(*member); //把member解引用,得到tmp::x,表示要訪問x
所以我們定義一個陣列,就可以迭代訪問類裡的各種int屬性了
int A:: *member [] = {&A::x, &A::y, &A::z};
for (int i = 0; i < 3; ++i)
cout << tmp.(*member[i]);
這個用途也可以放到成員函式上,構建一個函式列表,順序呼叫。
這麼個指標的行為跟一般的指標顯然不一樣,它不儲存地址,而是儲存一個“偏移量”,從物件地址開頭到物件成員的偏移量。這玩意其實可以輸出:
struct A{
int a, b, c;
};
main() {
printf("%d%d%d", &A::a, &A::b, &A::c); //! 輸入為0, 4, 8
//! 當然這玩意型別不是int,printf直接將他以int解析輸出了,所以cout達不到效果
}
這樣類成員指標的意義就很明顯了,假設一個A的物件t,那麼t的地址&t
和a的地址&(t.a)
是相等的,而&(t.b)
要多出來4,&(t.c)
又要多出來4。每個物件的記憶體構造都是一樣的,這個類成員指標就是獲取每個成員相對於頭地址的偏移量,這樣當我使用t.*member
編譯器就知道是頭地址+4處的變數,並且是個int。
不過成員函式又不太一樣了。不同物件的成員函式只有同一份程式短程式碼。C++不能用&(t.fun)
的方式獲取物件的成員函式的地址,要用取&A::fun
得到函式的地址。這個當然是真地址了。
類成員指標可以用於static
嗎?顯然不行,static成員單獨存放,與類本身無關,取&A::staticmember
得到的就是這個變數的正經地址。那可以用於virtual function
嗎?答案是可以,但是虛擬函式的地址無法確定,所以又變成了儲存偏移量,實際上儲存的是函式在虛表中的索引值。