C++:从子类访问父类的私有函数
生活随笔
收集整理的這篇文章主要介紹了
C++:从子类访问父类的私有函数
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
| C++:從子類訪問父類的私有函數 轉自 龍音閣http://blog.sina.com.cn/dragonsound 感謝原作者的工作 (2009-09-01 22:44:21) 標簽: 虛函數 c private f1 it? ? ? ???眾所周知,c和c++的數組都是不安全的,因為無論c還是c++都不提供數組邊界檢查功能,這使得數組溢出成為可能。從某個意義上說,c和c++是一種缺少監督的語言,然而這也正是其魅力所在。c++給予程序員更大的自由,相比于使用JAVA編程的束手束腳,c++程序員擁有了更大的權力,同時也擁有更多的機遇來玩弄一些技巧,比如說,從子類調用父類的私有函數。從子類調用父類的private函數?我沒聽錯么? 當然沒有! 盡管從各種c++書籍中我們得到的信息是子類從父類繼承的僅有protected成員和public成員,而父類的private成員無法被子類繼承,也無法被子類訪問,但是當父類的private函數是一個虛函數時,我們卻可以通過讀取VTABLE表中信息,從而找到父類虛函數的地址,進而調用它。 先回憶一下,c++的多態是怎樣實現的。 當c++的類中出現virtual關鍵字時,該類就擁有了一張VTABLE表。VTABLE表的內容包括了各個虛函數在虛擬內存中的偏移量,也就是說如果類A擁有三個虛函數:f1,f2,f3,那么在類A的虛函數表VTABLE中將依次存放f1,f2,f3的偏移地址。 那么,當類A僅擁有一個虛函數時,類A實例所占內存大小,也就是sizeof(A)與類A擁有兩個、三個,甚至更多個虛函數時的sizeof(A)有區別么?不,毫無區別。如果一個類的所有成員都是被virtual修飾的虛函數,那么當您使用sizeof(A)查看其大小時,結果無一例外的都是4——在32位系統中,四字節恰恰是一個整型數的大小,也恰恰是一個指針的大小。 這是為什么? 因為對于類A而言,它并不需要知道有多少個虛函數,它需要的僅僅是一個指向VTABLE的指針,這個指針通常被叫作vptr。它指向了VTABLE,至于究竟有多少個虛函數,只需在VTABLE中尋找就是。讓我們想象一下,vptr就向一個路標,它指向一個名叫VTABLE的公司,至于公司里有多少員工,你必須進入VTABLE公司才會知道。 好了,現在我們總結一下: 結論一:在有虛函數的類中,一定有一個vptr指向VTABLE 結論二:VTABLE中依次存儲了各個虛函數在虛擬內存中的偏移地址 現在,我們再來介紹另兩個c++的規律。 規律一:在任何類中,vptr一定存儲在該類實例的前四個字節中。 規律二:當子類和父類同時擁有虛函數時,子類的VTABLE中也同時會擁有父類和子類的虛函數偏移地址,而且子類的虛函數偏移地址一定是追加在父類虛函數偏移地址之后的。 也就是說,如果有如下兩個類: class A { private: virtual void WhoAmI() { cout << "I am class A" << endl; } }; class B:public A { public: void WhoAmIForB() { cout << "I am class B" << endl; } }; 那么,實例 A a; B b; 中各有一個vptr,其中a的vptr為(int*)(*(int*)(&a)),而b的vptr為(int*)(*(int*)(&b)), 這兩個vptr又分別指向各自的VTABLE,其中父類A的VTABLE中存儲的內容是:A::WhoAmI的偏移地址,而子類B的VTABLE呢? 子類B的VTABLE中依次存儲了A::WhoAmI的偏移地址,B::WhoAmIForB的偏移地址。 注意了,關鍵就在這里:A的虛函數都是私有的,不是么?但是編譯器鏈接器在此時卻似乎將關鍵字private忘記了,無論這些虛函數是private還是public的,它們的偏移地址都毫無例外的存放在了子類的VTABLE中! 這就是破綻!你可以刺出至命的一劍了! 我們既然知道子類實例的vptr,為什么不能推算出子類的VTABLE? 既然知道子類的VTABLE,根據規定律二,為什么不能推算出父類的虛函數偏移量? 答案就是:父類的第一個虛函數所在偏移量是(int*)(*(子類的vptr)),也就是——(int*)(*(int*)(*(int*)(&b)))。 當我們強制將其轉換為一個指向函數的指針時,就可以調用它,從而實現了從子類調用父類私有函數的行為。 試運行如下一段代碼: #include <iostream> using namespace std; class A { private: virtual void WhoAmI() { cout << "I am class A" << endl; } virtual void f0() { cout << "This is f0" << endl; } virtual void f1() { cout << "This is f1" << endl; } }; class B:public A { public: void WhoAmIForB() { cout << "I am class B" << endl; } }; typedef void (*FUNC)(); int main(int argc,char * argv[]) { B b; b.WhoAmIForB(); //b.WhoAmI(); error C2248: “A::WhoAmI”: 無法訪問 private 成員(在“A”類中聲明) FUNC func = (FUNC)((int*)(*(int*)(*(int*)(&b)))); func(); return 0; } |
總結
以上是生活随笔為你收集整理的C++:从子类访问父类的私有函数的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【推荐】LSI(latent seman
- 下一篇: C++继承机制