C++物件模型之記憶體佈局三(虛繼承)
阿新 • • 發佈:2018-12-03
經過兩天的摸索,今天終於搞清楚C++物件模型.前兩篇已經講解了單繼承,多重繼承和多繼承的物件模型.今天講解菱形繼承,雖然過程艱難,但是收穫豐富.
簡單虛繼承物件模型
首先編寫如下的測試程式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
using
namespace
std;
class A
{
public:
A(
int a1=
0,
int a2=
0):a1(a1),a2(a2){}
virtual |
- 當存在虛基類時,先是子類的成員,然後才是虛基類的成員.
通過在gdb下,輸入指令:
1 2 3 | set p obj on set p pretty on p *this(要執行到成員函式裡面) |
我在理解這個的時候,有分析過c物件呼叫虛基類的成員方法.通過反彙編程式碼,我發現當cp呼叫A中方法時,它先從C類的虛擬函式表首地址-24位元組處獲取A子物件相對於cp的偏移量16.所以C的虛擬函式表首地址負方向的空間還是有研究的地方。.
當我把C物件的函式f1改成f時,即重寫A中的f方法,這時cp中A的子物件中f方法將被C的f方法替換,但是程式輸出有錯,原因不明。如下:
菱形繼承下的物件模型
編寫如下程式:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | using namespace std; class A { public: A( int a1= 0, int a2= 0):a1(a1),a2(a2){} virtual void f(){ cout<< "A::f()"<< endl;} virtual void Af(){ cout<< "A::Af()"<< endl;} int a1; int a2; }; class B1: virtual public A { public: B1( int a1= 0, int a2= 0, int b1= 0):A(a1,a2),b1(b1){} virtual void f(){ cout<< "B1::f()"<< endl;} virtual void f1(){ cout<< "B1::f1()"<< endl;} virtual void Bf1(){ cout<< "B1::Bf1()"<< endl;} int b1; }; class B2: virtual public A { public: B2( int b2= 0):b2(b2){} virtual void f(){ cout<< "B2::f()"<< endl;} virtual void f2(){ cout<< "B2::f2()"<< endl;} virtual void Bf2(){ cout<< "B2::Bf2()"<< endl;} int b2; }; class C: public B1, public B2 { public: C( int a1= 0, int a2= 0, int b1= 0, int b2= 0, int c1= 0):B1( 1, 2, 3),B2( 6),c1( 7){} virtual void f(){ cout<< "C::f()"<< endl;} virtual void f1(){ cout<< "C::f1()"<< endl;} virtual void f2(){ cout<< "C::f2()"<< endl;} virtual void Cf(){ cout<< "C::Cf()"<< endl;} int c1; }; typedef void (*pfun)(); int main(void) { C *cp= new C; cout<< sizeof(*bp)<< endl; pfun fun= NULL; cout<< "The B1's virtual table->"<< endl; for( int i= 0;i< 5;i++) { fun=(pfun)*(( long*)*( long*)cp+i); fun(); } long* p=( long*)cp+ 2; cout<< "The B2's virtual table->"<< endl; for( int i= 0;i< 3;i++) { fun=(pfun)*(( long*)*( long*)p+i); fun(); } cout<< "The A2's virtual table->"<< endl; A *ap= reinterpret_cast<A*>(( long*)cp+ 4); for( int i= 0;i< 2;i++) { fun=(pfun)*(( long*)*( long*)ap+i); fun(); } return 0; } |
此時程式輸出仍然有錯,因為c重寫了A中的方法。原因不明。c物件模型為:
如果c不重寫A的f方法,即將A的f方法改為f0,則程式輸出如下:
轉載:http://luodw.cc/2015/10/08/Cplus3/