參考《如果你已經熟悉常規指標的宣告語法,那麼宣告乙個"指向類成員變數的指標"並不複雜:
int *ip;//乙個指向int變數的指標
int c::*ip;//乙個指向c類中int成員變數的指標
你必須要做的就是多寫乙個classname::來限定這個指標到底指向哪個類
乙個常規的指標包含乙個位址.如果解引用該指標,就會得到該位址的物件:
int a = 12;
int *ip;
ip = &a;
*ip = 0;
a = *ip;
但是乙個"指向類成員變數的指標"並不包含乙個位址,簡單點說,實際上它是乙個成員變數在類中的偏移量.當然,嚴格點說,因為c++標準並為對"指向類成員變數的指標"如何實現
做任何規定,說"指向類成員變數的指標"是乙個整數的偏移量就不是一定正確,但是,大多數編譯器確實是這樣做的.下面我們看看"指向類成員變數的指標"是如何使用的?
#include "stdafx.h"
struct cpoint
;void print(cpoint* point, double cpoint::* p)
int main(int argc, char* argv)
double cpoint::* p = null;
這是"指向類成員變數的指標"的宣告,只是多了乙個cpoint::而已,這個指標指向cpoint類中double型別的成員變數
p = &cpoint::x;
這是"指向類成員變數的指標"的賦值,記住,它是乙個偏移量而不是位址,因此必須用這種靜態的寫法,這裡不能用有位址的物件pt來賦值
double x = pt.*p;
這是"指向類成員變數的指標"的解引用,記住,解引用必須有實際的位址,因為必須用有位址的物件pt來解引用,.*的語法有些怪異,不過我寧願把它拆解為pt.和*p兩部分來理解
printf("%f/n", point->*p);
這也是"指向類成員變數的指標"的解引用, 和.*同樣的道理,如果我們有乙個指向cpoint的指標,我們就必須使用->*來解引用,你也可以把->*拆解為point->和*p兩部分來理解
int offset = (int&)p;
這裡把"指向類成員變數的指標"直接轉換為int,這裡的offset=8,恰好是cpoint類中的成員變數y在類中的偏移量,驗證了我們說的"指向類成員變數的指標"是乙個偏移量的說法
不過,我還是忍不住奉勸各位,盡量不要直接使用這個偏移量,這畢竟是編譯器內部實現的細節,實在有太多的人喜歡這種黑客似的**並四處炫耀,真正的"指向類成員變數的指標"
的用法只應該包括宣告,賦值和解引用
加上派生又如何?
#include "stdafx.h"
struct cpoint
;struct cpoint3d : public cpoint
;void print(cpoint* point, double cpoint::* p)
int main(int argc, char* argv)
offset = (int&)p3d;
這裡的offset=16,正是cpoint3d中的成員變數z在類中的偏移量,有沒有人說offset=0的,重新去看看c++的物件模型
p3d = p; //正確
存在基類的"指向類成員變數的指標"到派生類的"指向類成員變數的指標"的隱式轉換,其含義無疑是說基類的成員變數偏移量只是派生類中成員變數偏移量的乙個子集,
因此這樣的轉換應該是沒有問題的,但是反過來呢?
//p = p3d; //錯誤
不存在派生類的"指向類成員變數的指標"到基類的"指向類成員變數的指標"的隱式轉換,因為派生類中的成員變數並不一定能夠在基類中找到
"指向類成員變數的指標"基類和派生類的關係和"指向類物件的指標"基類和派生類的關係完全相反,就"指向類成員變數的指標"的本質來說,這是合理的,但是這樣的話,
我們就無法利用公共的print函式了,除非...
p = (double cpoint::*)p3d; //強制轉換
我們做強制轉換是可以的
cpoint3d pt3d;
pt3d.z = 30;
print(&pt3d, (double cpoint::*)p3d);
而且也只有強制轉換才可以利用公共的print函式了,這裡的print列印出來的是30,沒有錯誤的,因為我們傳入的是指向cpoint3d物件的指標,成員變數的偏移量也沒有錯誤
但是是否一定要這樣做呢?這取決於程式設計師自己的選擇
參考《我們首先複習一下"指向函式的指標"如何使用?
void print()
void (*pfun)(); //宣告乙個指向函式的指標,函式的引數是void,函式的返回值是void
pfun = print; //賦值乙個指向函式的指標
(*pfun)(); //使用乙個指向函式的指標
比較簡單,不是嗎?為什麼*pfun需要用()擴起來呢?因為*的運算子優先順序比()低,如果不用()就成了*(pfun())
"指向類成員函式的指標"比"指向函式的指標"就多了個類的區別:
struct cpoint
void minus(double x_, double y_)
void mul(double x_, double y_)
void dev(double x_, double y_)
virtual void move(double x_, double y_)
double x;
double y;
};void oper(cpoint* ppoint, void (cpoint::*pfun)(double x_, double y_), int x, int y)
struct cpoint3d : public cpoint
};int main(int argc, char* argv)
void (cpoint::*pfun)(double x_, double y_);
這裡是"指向類成員函式的指標"的宣告,就是多了cpoint::的限定
pfun = &cpoint::plus;
這裡是"指向類成員函式的指標"的賦值,在賦值的時候必須用這種靜態的方式
(pt.*pfun)(10, 10);
這裡是"指向類成員函式的指標"的使用,記住,解引用必須有實際的this指標位址,因此必須用有位址的物件pt來解引用,.*的語法有些怪異,不過我寧願把它拆解為pt.和*pfun兩部分來理解
offset = (int&)pfun;
這裡offset=4198410,當然不同的專案,不同的編譯器這個值是不同的,由此也可以知道,"指向類成員函式的指標"確實是乙個指標,其實由c++物件模型我們就應該知道這個結論了
,在c++物件模型中,成員函式是全域性的,並不屬於物件
有人想用這個值嗎?或許可以用下面的**:
void (cpoint::*pfun2)(double x_, double y_);
memcpy(&pfun2, &offset, sizeof(int));
oper(&pt, pfun2, 10, 10);
不過,我還是忍不住奉勸各位,盡量不要直接使用這個值,這畢竟是編譯器內部實現的細節,實在有太多的人喜歡這種黑客似的**並四處炫耀,真正的"指向類成員函式的指標"
的用法只應該包括宣告,賦值和解引用
pfun = &cpoint::move;
注意到這裡的move是虛函式,那麼這裡還支援虛函式的多型嗎?沒有問題,"指向類成員函式的指標"支援多型,當然了,代價是,這時候這個指標就必須擴充套件為乙個結構了,c++為了
"指向類成員函式的指標"支援多型是要付出代價的
p3dfun = pfun; //正確
存在基類的"指向類成員函式的指標"到派生類的"指向類成員函式的指標"的隱式轉換,其含義無疑是說基類的成員函式布局資訊只是派生類中成員函式布局資訊的乙個子集,
因此這樣的轉換應該是沒有問題的,但是反過來呢?
//pfun = p3dfun; //錯誤
不存在派生類的"指向類成員函式的指標"到基類的"指向類成員函式的指標"的隱式轉換,因為派生類中的成員函式並不一定能夠在基類中找到
"指向類成員函式的指標"基類和派生類的關係和"指向類物件的指標"基類和派生類的關係完全相反,就"指向類成員函式的指標"的本質來說,這是合理的,但是這樣的話,
我們就無法利用公共的oper函式了,除非...
pfun = (void (cpoint::*)(double, double))p3dfun; //強制轉換
我們做強制轉換是可以的
oper(&pt3d, (void (cpoint::*)(double, double))p3dfun, 10, 10);
而且也只有強制轉換才可以利用公共的oper函式了,這裡的oper呼叫的是pt3d中的move函式,沒有錯誤的
但是是否一定要這樣做呢?這取決於程式設計師自己的選擇
指向類成員變數的指標並非指標
參考 如果你已經熟悉常規指標的宣告語法,那麼宣告乙個 指向類成員變數的指標 並不複雜 int ip 乙個指向int變數的指標 int c ip 乙個指向c類中int成員變數的指標 你必須要做的就是多寫乙個classname 來限定這個指標到底指向哪個類 乙個常規的指標包含乙個位址.如果解引用該指標,...
指向類成員的指標並非指標
指向類成員的指標並非指標 對於指向類成員的指標,必須緊記,指向類成員 非static 的指標並非指標。1 與常規指標不同,乙個指向成員的指標並不指向乙個具體的記憶體位置,它指向的是乙個類的特定成員,而不是指向特定物件裡的特定成員。通常最清晰的做法,是將指向資料成員的指標看作為乙個偏移量。這個偏移量告...
指向類成員的指標
一 指向類的普通成員的指標 非靜態 1 指向類成員函式的指標 簡單的講,指向類成員函式的指標與普通函式指標的區別在於,前者不僅要匹配函式的引數型別和個數以及返回值型別,還要匹配該函式指標所屬的類型別。總結一下,比較以下幾點 a 引數型別和個數 b 返回值型別 c 所屬的類型別 特別之處 究其原因,是...