1. 什么是菱形继承
基类A,B继承A,C继承A,D继承BC。D中的B对象有A,D中的C对象还有A,重复了,如果调用函数,则不知道是B中的函数还是C中的函数。
#include <iostream>
using namespace std;
class A {
public:
A() { a = 1; }
~A() {}
void fun() { cout << "in class A" << endl; }
int a;
};
class B : public A {
public:
B() { b = 2; }
~B() {}
void fun() { cout << "in class B" << endl; }
int b;
};
class C : public A {
public:
C() { c = 3; }
~C() {}
void fun() { cout << "in class C" << endl; }
int c;
};
class D : public B, public C {
public:
D() { d = 4; }
~D() {}
int d;
};
int main() {
D od;
//od.fun();//会报错,fun不明确,不知道是谁的fun
auto add_ba = &od.B::A::a;
auto add_ca = &od.C::A::a;
cout << "addr of a in B = " << add_ba << endl;
cout << "addr of a in C = " << add_ca << endl;
return 0;
}
输出:
B中有个A对象,C中有个A对象,两个A对象不一样,D中就有两个A对象。
菱形继承存在二义性与数据冗余问题。
使用虚继承解决,虚继承的做法如下。
2. 虚继承
虚继承的具体操作方式如下:
#include <iostream>
using namespace std;
class A {
public:
A() { a = 1; }
~A() {}
void fun() { cout << "in class A" << endl; }
int a;
};
class B : virtual public A {
public:
B() { b = 2; }
~B() {}
void fun() { cout << "in class B" << endl; }
int b;
};
class C : virtual public A {
public:
C() { c = 3; }
~C() {}
void fun() { cout << "in class C" << endl; }
int c;
};
class D : public B, public C {
public:
D() { d = 4; }
~D() {}
int d;
};
int main() {
D od;
//od.fun();
auto add_ba = &od.B::A::a;
auto add_ca = &od.C::A::a;
cout << "addr of a in B = " << add_ba << endl;
cout << "addr of a in C = " << add_ca << endl;
return 0;
}
实际中的内存关系如下:
此时D类对象od的布局如左侧所示,先是B类对象(B类对象此时只包含一个指针和b),然后是C类对象(C类对象此时只包含一个指针和c),然后是D类独有的d,最后是A类对象中的a。
此时的结构有些奇怪:
B中的a与C中的a地址相同:
没有了冗余现象,具体来说是通过B类对象和C类对象的指针实现的,指针指向的区域存储的是该类对象到基类对象的一个偏移量,如B中的指针就是存储的B类对象到A类对象的偏移量,一个指针4个字节,偏移量为20说明相差5个指针的距离。
sizeod(od)=24
,abcd占16个字节,B中的指针和C中的指针一共8字节,加起来为24.