亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 編程 > C++ > 正文

關于C++對象繼承中的內存布局示例詳解

2020-01-26 13:58:50
字體:
來源:轉載
供稿:網友

前言

本文給大家介紹的是關于C++對象繼承的內存布局的相關內容,分享出來供大家參考學習,在開始之前說明下,關于單繼承和多繼承的簡單概念可參考此文章

以下編譯環境均為:WIN32+VS2015

虛函數表

對C++ 了解的人都應該知道虛函數(Virtual Function)是通過一張虛函數表(Virtual Table)來實現的。簡稱為V-Table。在這個表中,主是要一個類的虛函數的地址表,這張表解決了繼承、覆蓋的問題,保證其容真實反應實際的函數。

首先先通過一個例子來引入虛函數表,假如現在有三個類如下:

class A //包含虛函數的類{public: virtual void func1() {} virtual void func2() {}};class B//空類{};class C //包含成員函數不包含成員變量的類{ void fun() {}};void Test1(){ cout << sizeof(A) << endl; cout << sizeof(B) << endl; cout << sizeof(C) << endl;}

就上述的代碼,將會分別輸出4,1,1

造成A的大小為4的原因就是:在A中存放了一個指向A類的虛函數表的指針。而32位下一個指針大小為4字節,所以就為4。

A類實例化后在內存中對應如下:

注:在虛函數表中用0來結尾。

通過內存中的顯示我們就能知道編譯器應該將虛函數表的指針存在于對象實例中最前面的位置,所以可以&a轉成int*,取得虛函數表的地址,再強轉成(int*)方便接下來可以每次只訪問四個字節大?。ㄌ摵瘮当砜煽醋鍪且粋€函數指針數組,由于32位下指針是4字節,所以轉為(int*))。將取得的int*指針傳給下面的打印虛函數表的函數,就能夠打印出對應的地址信息。

typedef void(*FUNC) ();//int*VTavle = (int*)(*(int*)&a)//傳參完成后就可打印出對應的信息。void PrintVTable(int* VTable){ cout << " 虛表地址>" << VTable << endl; for (int i = 0; VTable[i] != 0; ++i) { printf(" 第%d個虛函數地址 :0X%x,->", i, VTable[i]); FUNC f = (FUNC)VTable[i]; f(); } cout << endl;}

接下來就來分析各種繼承關系中對應的內存模型以及虛函數表

單繼承(無虛函數覆蓋)

class A{public: virtual void func1() { cout << "A::func1" << endl; } virtual void func2() { cout << "A::func2" << endl; }public: int _a;};class B : public A{public: virtual void func3() { cout << "B::func3" << endl; } virtual void func4() { cout << "B::func4" << endl; }public: int _b;};void Test1(){ B b; b._a = 1; b._b = 2; int* VTable = (int*)(*(int*)&b); PrintVTable(VTable);}

將內存中的顯示和我們寫的顯示虛函數表對應起來如下:

小結:

1)虛函數按照其聲明順序放于表中。

2)父類的虛函數在子類的虛函數前面。(由于子類單繼承父類,直接使用父類的虛函數表)

一般繼承(成員變量+虛函數覆蓋)

在上面例子進行稍微修改,使得子類中有對父類虛函數的覆蓋,進行和之前同樣的測試:

class A{public: virtual void func1() { cout << "A::func1" << endl; } virtual void func2() { cout << "A::func2" << endl; }public: int _a;};class B : public A{public: virtual void func1() { cout << "B::func1" << endl; } virtual void func3() { cout << "B::func3" << endl; }public: int _b;};

小結:

1)覆蓋的func()函數被放到了虛表中原來父類虛函數的位置。

2)沒有被覆蓋的函數依舊。

多重繼承(成員變量+虛函數覆蓋)

class A{public: virtual void func1() { cout << "A::func1" << endl; } virtual void func2() { cout << "A::func2" << endl; }public: int _a;};class B {public: virtual void func3() { cout << "B::func1" << endl; }public: int _b;};class C : public A , public B{ //覆蓋A::func1() virtual void func1() { cout << "C::func1()"<<endl; } virtual void func4() { cout << "C::func4()" << endl; }public: int _c;};

再次調試觀察:

小結:

多重繼承后的子類將與自己第一個繼承的父類公用一份虛函數表。(上述例子中A為C的第一個繼承類)

菱形繼承(成員變量 + 虛函數覆蓋)

class A{public: virtual void func1() { cout << "A::func1" << endl; }public: int _a;};class B : public A{public: virtual void func2() { cout << "B::func2" << endl; }public: int _b;};class C : public A { virtual void func3() { cout << "C::func3()" << endl; }public: int _c;};class D : public B , public C{ virtual void func2() { cout << "D::fun2()" << endl; } virtual void func4() { cout << "D::fun4()" << endl; }public: int _d;};void Test1(){ D d; d.B::_a = 1; d.C::_a = 2; d._b = 3; d._c = 4; d._d = 5; int* VTable = (int*)(*(int*)&d); PrintVTable(VTable);}

掌握了單繼承和多繼承的規律,按照總結的一步步分析,就可以最終得到D的虛函數表。

由于子類B繼承父類A,所以B與A公用一個虛函數表,又因為B是D多繼承中的第一個繼承的類,所以B,D共用一個虛函數表。

菱形的虛擬繼承(成員變量 + 虛函數覆蓋)

參考下面這個例子:

class A{public: virtual void func1() { cout << "A::func1()" << endl; } virtual void func2() { cout << "A::func2()" << endl; }public: int _a;};class B : virtual public A//虛繼承A,覆蓋func1(){public: virtual void func1() { cout << "B::func1()" << endl; } virtual void func3() { cout << "B::func3()" << endl; }public: int _b;};class C : virtual public A //虛繼承A,覆蓋func1(){ virtual void func1() { cout << "C::func1()" << endl; } virtual void func3() { cout << "C::func3()" << endl; }public: int _c;};class D : public B , public C//虛繼承B,C,覆蓋func1(){ virtual void func1() { cout << "D::func1()" << endl; } virtual void func4() { cout << "D::func4()" << endl; }public: int _d;};typedef void(*FUNC) ();void PrintVTable(int* VTable){ cout << " 虛表地址>" << VTable << endl; for (int i = 0; VTable[i] != 0; ++i) { printf(" 第%d個虛函數地址 :0X%x,->", i, VTable[i]); FUNC f = (FUNC)VTable[i]; f(); } cout << endl;}void Test1(){ D d; d.B::_a = 1; d.C::_a = 2; d._b = 3; d._c = 4; d._d = 5; cout <<"sizeof(A) = "<< sizeof(A) << endl; cout << "sizeof(B) = " << sizeof(B) << endl; cout << "sizeof(C) = " << sizeof(C) << endl; //打印d的虛函數表 int* VTable = (int*)(*(int*)&d); PrintVTable(VTable); //打印C的虛函數表 VTable = (int*)*(int*)((char*)&d + sizeof(B)-sizeof(A));  PrintVTable(VTable); //打印A的虛函數表 VTable = (int*)*(int*)((char*)&d + sizeof(B)+sizeof(C)-2*sizeof(A)+4);  PrintVTable(VTable);}

接下來就慢慢分析:

1)先通過調試查看內存中是如何分配的,并和我們打印出的虛函數表對應起來:

注:由于B,C是虛繼承A,所以編譯器為了解決菱形繼承所帶來的“二義性”以及“數據冗余”,便將A放在最末端,并在子類中存放一個虛基表,方便找到父類;而虛基表的前四個字節存放的是對于自己虛函數表的偏移量,再往下四個字節才是對于父類的偏移量。

2)接下來就抽象出來分析模型

總結

1)虛函數按照其聲明順序放于表中;

2)父類的虛函數在子類的虛函數前面(由于子類單繼承父類,直接使用父類的虛函數表);

3)覆蓋的func()函數被放到了虛表中原來父類虛函數的位置;

4)沒有被覆蓋的函數依舊;

5)如果B,C虛繼承A,并且B,C內部沒有再聲明或定義虛函數,則B,C沒有對應的虛函數表;

6)在菱形的虛擬繼承中,要注意A為B,C所共有的,在打印對應虛函數表時要注意偏移量。

好了,以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作能帶來一定的幫助,如果有疑問大家可以留言交流,謝謝大家對武林網的支持。

發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
中文字幕亚洲欧美日韩高清| 国产人妖伪娘一区91| 亚洲r级在线观看| 夜夜嗨av一区二区三区免费区| 欧美伦理91i| 九九热精品在线| 国产在线98福利播放视频| 亚洲国产日韩欧美综合久久| 亚洲最大av在线| 亚洲免费视频在线观看| 91九色国产在线| 亚洲免费人成在线视频观看| 亚洲午夜国产成人av电影男同| 亚洲二区在线播放视频| 亚洲欧洲一区二区三区在线观看| 亚洲美女动态图120秒| 综合久久五月天| 人人做人人澡人人爽欧美| 中文字幕欧美国内| 亚洲精品永久免费精品| 欧美黄色片视频| 国内揄拍国内精品少妇国语| 人九九综合九九宗合| 国产精品爱久久久久久久| 麻豆国产精品va在线观看不卡| 国产精品亚洲综合天堂夜夜| 欧美成人四级hd版| 久久久久久噜噜噜久久久精品| 亚洲天堂视频在线观看| 狠狠躁夜夜躁人人爽天天天天97| 欧美黑人国产人伦爽爽爽| 欧美专区在线观看| 国产+成+人+亚洲欧洲| 欧美激情第一页xxx| 亚洲黄色www| 国产精品成人av性教育| 欧美在线免费观看| 久久精品视频在线播放| 亚洲毛片在线观看| 97色在线视频观看| 蜜臀久久99精品久久久无需会员| 少妇av一区二区三区| 欧美国产第一页| 久热爱精品视频线路一| 久久精品99久久久香蕉| 欧美日韩另类视频| 亚洲午夜女主播在线直播| 成人免费淫片视频软件| 欧美国产日韩xxxxx| 亚洲精品久久7777777| 欧美激情在线播放| 亚洲精品www久久久久久广东| 国内精品美女av在线播放| 国产999视频| 中文字幕九色91在线| 亚洲国产成人在线播放| 一区二区在线免费视频| 亚洲桃花岛网站| 亚洲伊人久久综合| 欧美日韩ab片| 国产精品视频一| 日av在线播放中文不卡| 韩日欧美一区二区| 岛国av一区二区在线在线观看| 亚洲人成网7777777国产| 日韩在线视频导航| 欧美黑人又粗大| 久久久欧美一区二区| 欧美成人精品xxx| 日韩福利伦理影院免费| 亚洲视频专区在线| 国产激情999| 国产a∨精品一区二区三区不卡| 日韩亚洲欧美中文在线| 国产视频精品va久久久久久| 亚洲美女www午夜| 亚洲欧美日韩在线高清直播| 97婷婷大伊香蕉精品视频| 国产精品久久久久久久9999| 成人激情黄色网| 色在人av网站天堂精品| 97精品国产aⅴ7777| 国产亚洲激情在线| 精品国产乱码久久久久久天美| 日韩中文字幕在线看| 欧美性高潮床叫视频| 欧美大尺度电影在线观看| 欧美三级欧美成人高清www| 精品亚洲一区二区三区在线观看| …久久精品99久久香蕉国产| 中文欧美在线视频| 91精品国产综合久久男男| 日韩精品高清在线观看| 成人黄色av网| 91免费欧美精品| 欧美日韩亚洲视频一区| 日韩最新免费不卡| 在线日韩日本国产亚洲| 在线视频一区二区| 欧美激情18p| 欧美中文在线免费| 91精品国产91久久久久久最新| 中文字幕日韩av| 亚洲美女精品久久| 欧美性猛交丰臀xxxxx网站| 国语自产精品视频在免费| 国产亚洲aⅴaaaaaa毛片| 欧美国产第一页| 久久亚洲精品小早川怜子66| 日韩美女视频中文字幕| 欧美劲爆第一页| 777午夜精品福利在线观看| 亚洲精品自拍偷拍| 疯狂做受xxxx高潮欧美日本| 亚洲jizzjizz日本少妇| 91精品国产91久久久久福利| 亚洲精品有码在线| 久久免费视频在线| 欧美精品在线免费观看| 欧美影院在线播放| 国外成人性视频| 福利精品视频在线| 亚洲自拍偷拍视频| 欧美老肥婆性猛交视频| 日韩av第一页| 午夜精品一区二区三区在线视| 色妞久久福利网| 欧美一区二区三区艳史| 日本高清不卡的在线| 国产视频久久网| 久久精品视频在线| 久久久综合免费视频| 久久久精品中文字幕| 亚洲色图50p| 久久久在线视频| 精品国产91乱高清在线观看| 久久6免费高清热精品| www.国产一区| 热久久这里只有精品| 国产精品嫩草影院久久久| 国产精品久久久久久一区二区| 日本精品免费一区二区三区| 亚洲午夜女主播在线直播| 中文字幕亚洲欧美一区二区三区| 欧美重口另类videos人妖| 正在播放国产一区| 亚洲精品国产精品自产a区红杏吧| 日韩中文字幕在线观看| 亚洲精品国产精品国产自| 992tv成人免费视频| 国产精品扒开腿做爽爽爽男男| 日韩中文在线中文网在线观看| 国内精品美女av在线播放| 午夜精品久久久久久99热软件| 国产第一区电影| 亚洲自拍偷拍一区| 成人免费自拍视频| 日韩av影片在线观看| 亚洲国产精品女人久久久| 午夜精品三级视频福利| 亚洲欧美日韩天堂| 亚洲韩国日本中文字幕| 一区二区三区国产视频| 91精品国产自产在线老师啪|