经过两天的摸索,今天终于搞清楚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 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;
}
|
- 当存在虚基类时,先是子类的成员,然后才是虚基类的成员.
通过在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/