C++对象模型之内存布局三(虚继承)

经过两天的摸索,今天终于搞清楚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
 
      
#include <iostream>
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 C: virtual public A
{
public:
C( int a1= 1, int a2= 2, int c1= 4):A(a1,a2),c1(c1){
}
virtual void f1(){ cout<< "C::f1()"<< endl;}
virtual void cf(){ cout<< "C::cf()"<< endl;}
int c1;
};
typedef void (*pfun)();
int main(void)
{
C *cp= new C;
pfun fun= NULL;
cout<< "The C's virtual table->"<< endl;
for( int i= 0;i< 2;i++)
{
fun=(pfun)*(( long*)*( long*)cp+i);
fun();
}
cout<< "c1="<<*(( int*)cp+ 2)<< endl;
cout<< "The A's virtual table->"<< endl;
long* p=( long*)cp+ 2;
for( int i= 0;i< 2;i++)
{
fun=(pfun)*(( long*)*( long*)p+i);
fun();
}
cout<< "a1="<<*(( int*)p+ 2)<< endl;
cout<< "a2="<<*(( int*)p+ 3)<< endl;
return 0;
}

上述程序的输出如下:简单虚基类验证程序输出简单解释下:

  1. 当存在虚基类时,先是子类的成员,然后才是虚基类的成员.

以下是C对象的对象模型:简单虚继承对象模型

通过在gdb下,输入指令:

 
      
1
2
3
 
      
set p obj on
set p pretty on
p *this(要运行到成员函数里面)

也可以输出C对象的对象模型.截图如下:通过gdb显示C对象模型

我在理解这个的时候,有分析过c对象调用虚基类的成员方法.通过反汇编代码,我发现当cp调用A中方法时,它先从C类的虚函数表首地址-24字节处获取A子对象相对于cp的偏移量16.所以C的虚函数表首地址负方向的空间还是有研究的地方。.

当我把C对象的函数f1改成f时,即重写A中的f方法,这时cp中A的子对象中f方法将被C的f方法替换,但是程序输出有错,原因不明。如下:C重写A的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
 
      
#include <iostream>
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,则程序输出如下:将A的f方法改为f0

转载:http://luodw.cc/2015/10/08/Cplus3/

猜你喜欢

转载自blog.csdn.net/zhang_guyuan/article/details/78019536