日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > c/c++ >内容正文

c/c++

C++:从子类访问父类的私有函数

發(fā)布時(shí)間:2025/4/14 c/c++ 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 C++:从子类访问父类的私有函数 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
C++:從子類訪問(wèn)父類的私有函數(shù)
轉(zhuǎn)自 龍音閣http://blog.sina.com.cn/dragonsound 感謝原作者的工作
(2009-09-01 22:44:21)

標(biāo)簽: 虛函數(shù) c private f1 it? ? ? ???眾所周知,c和c++的數(shù)組都是不安全的,因?yàn)闊o(wú)論c還是c++都不提供數(shù)組邊界檢查功能,這使得數(shù)組溢出成為可能。從某個(gè)意義上說(shuō),c和c++是一種缺少監(jiān)督的語(yǔ)言,然而這也正是其魅力所在。c++給予程序員更大的自由,相比于使用JAVA編程的束手束腳,c++程序員擁有了更大的權(quán)力,同時(shí)也擁有更多的機(jī)遇來(lái)玩弄一些技巧,比如說(shuō),從子類調(diào)用父類的私有函數(shù)。從子類調(diào)用父類的private函數(shù)?我沒(méi)聽(tīng)錯(cuò)么?
當(dāng)然沒(méi)有!
盡管從各種c++書籍中我們得到的信息是子類從父類繼承的僅有protected成員和public成員,而父類的private成員無(wú)法被子類繼承,也無(wú)法被子類訪問(wèn),但是當(dāng)父類的private函數(shù)是一個(gè)虛函數(shù)時(shí),我們卻可以通過(guò)讀取VTABLE表中信息,從而找到父類虛函數(shù)的地址,進(jìn)而調(diào)用它。

先回憶一下,c++的多態(tài)是怎樣實(shí)現(xiàn)的。
當(dāng)c++的類中出現(xiàn)virtual關(guān)鍵字時(shí),該類就擁有了一張VTABLE表。VTABLE表的內(nèi)容包括了各個(gè)虛函數(shù)在虛擬內(nèi)存中的偏移量,也就是說(shuō)如果類A擁有三個(gè)虛函數(shù):f1,f2,f3,那么在類A的虛函數(shù)表VTABLE中將依次存放f1,f2,f3的偏移地址。
那么,當(dāng)類A僅擁有一個(gè)虛函數(shù)時(shí),類A實(shí)例所占內(nèi)存大小,也就是sizeof(A)與類A擁有兩個(gè)、三個(gè),甚至更多個(gè)虛函數(shù)時(shí)的sizeof(A)有區(qū)別么?不,毫無(wú)區(qū)別。如果一個(gè)類的所有成員都是被virtual修飾的虛函數(shù),那么當(dāng)您使用sizeof(A)查看其大小時(shí),結(jié)果無(wú)一例外的都是4——在32位系統(tǒng)中,四字節(jié)恰恰是一個(gè)整型數(shù)的大小,也恰恰是一個(gè)指針的大小。
這是為什么?
因?yàn)閷?duì)于類A而言,它并不需要知道有多少個(gè)虛函數(shù),它需要的僅僅是一個(gè)指向VTABLE的指針,這個(gè)指針通常被叫作vptr。它指向了VTABLE,至于究竟有多少個(gè)虛函數(shù),只需在VTABLE中尋找就是。讓我們想象一下,vptr就向一個(gè)路標(biāo),它指向一個(gè)名叫VTABLE的公司,至于公司里有多少員工,你必須進(jìn)入VTABLE公司才會(huì)知道。

好了,現(xiàn)在我們總結(jié)一下:
結(jié)論一:在有虛函數(shù)的類中,一定有一個(gè)vptr指向VTABLE
結(jié)論二:VTABLE中依次存儲(chǔ)了各個(gè)虛函數(shù)在虛擬內(nèi)存中的偏移地址
現(xiàn)在,我們?cè)賮?lái)介紹另兩個(gè)c++的規(guī)律。
規(guī)律一:在任何類中,vptr一定存儲(chǔ)在該類實(shí)例的前四個(gè)字節(jié)中。
規(guī)律二:當(dāng)子類和父類同時(shí)擁有虛函數(shù)時(shí),子類的VTABLE中也同時(shí)會(huì)擁有父類和子類的虛函數(shù)偏移地址,而且子類的虛函數(shù)偏移地址一定是追加在父類虛函數(shù)偏移地址之后的。
也就是說(shuō),如果有如下兩個(gè)類:
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;
}
};

那么,實(shí)例
A a;
B b;
中各有一個(gè)vptr,其中a的vptr為(int*)(*(int*)(&a)),而b的vptr為(int*)(*(int*)(&b)),
這兩個(gè)vptr又分別指向各自的VTABLE,其中父類A的VTABLE中存儲(chǔ)的內(nèi)容是:A::WhoAmI的偏移地址,而子類B的VTABLE呢?
子類B的VTABLE中依次存儲(chǔ)了A::WhoAmI的偏移地址,B::WhoAmIForB的偏移地址。

注意了,關(guān)鍵就在這里:A的虛函數(shù)都是私有的,不是么?但是編譯器鏈接器在此時(shí)卻似乎將關(guān)鍵字private忘記了,無(wú)論這些虛函數(shù)是private還是public的,它們的偏移地址都毫無(wú)例外的存放在了子類的VTABLE中!
這就是破綻!你可以刺出至命的一劍了!

我們既然知道子類實(shí)例的vptr,為什么不能推算出子類的VTABLE?
既然知道子類的VTABLE,根據(jù)規(guī)定律二,為什么不能推算出父類的虛函數(shù)偏移量?
答案就是:父類的第一個(gè)虛函數(shù)所在偏移量是(int*)(*(子類的vptr)),也就是——(int*)(*(int*)(*(int*)(&b)))。
當(dāng)我們強(qiáng)制將其轉(zhuǎn)換為一個(gè)指向函數(shù)的指針時(shí),就可以調(diào)用它,從而實(shí)現(xiàn)了從子類調(diào)用父類私有函數(shù)的行為。

試運(yùn)行如下一段代碼:
#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”: 無(wú)法訪問(wèn) private 成員(在“A”類中聲明)



FUNC func = (FUNC)((int*)(*(int*)(*(int*)(&b))));
func();

return 0;
}

總結(jié)

以上是生活随笔為你收集整理的C++:从子类访问父类的私有函数的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。