菱形继承就是两个子类继承同一个父类,而又有子类同时继承这两个子类。
创建一个基类A让B1和B2公有继承于它,让C公有继承B1和B2。
class A
{
public :
A()
:a(1)
{
cout << "A()" << endl;
}
~A()
{
cout << "~A()" << endl;
}
int a;
};
class B1 : public A
{
public :
B1()
:b1(2)
{
cout << "B1()" << endl;
}
~B1()
{
cout << "~B1()" << endl;
}
int b1;
};
class B2 : public A
{
public:
B2()
:b2(3)
{
cout << "B2()" << endl;
}
~B2()
{
cout << "~B2()" << endl;
}
int b2;
};
class C : public B1,public B2
{
public:
C()
:c(4)
{
cout << "C()" << endl;
}
~C()
{
cout << "~C()" << endl;
}
int c;
};
这时候B1.B2中分别有两个变量,一个是本身的变量,另外一个是继承过来的。而C则有五个变量。如下图:
在创建C类对象时,先去调用了B1类的构造函数,在B1的构造函数中又去调用了A类的构造函数,返回C类的构造函数中后接着调用B2的构造函数,在B2的构造函数中又去调用A的构造函数。
当要通过C类对象去访问A类的成员时会出现二义性问题,因为编译器不知道你要访问的是B1类中所包含的A类成员还是B2类中所包含的A类成员。在C类对象构造的构成中,A类的构造函数被执行了两次(B1和B2分别执行一次),会创建出两个完全一样的问题,这就造成了数据冗余问题。
菱形虚拟继承
我们引入了虚继承来解决上面的二义性问题和数据冗余的问题。虚拟继承的目的是让某个类作出声明,承诺愿意共享它的基类。
- 虚继承解决了在菱形继承体系里面子类对象包含多份父类对象的数据冗余&浪费空间的问题。
- 虚继承体系看起来好复杂,在实际应用我们通常不会定义如此复杂的继承体系。
- 一般不到万不得已都不要定义菱形结构的虚继承体系结构,因为使用虚继承解决数据冗余问题也带来了性能上的损耗。
创建一个基类A让B1和B2虚继承于它,让C公有继承B1和B2,这时B1和B2就共享了基类A。
class A
{
public :
A()
:a(1)
{
cout << "A()" << endl;
}
~A()
{
cout << "~A()" << endl;
}
int a;
};
class B1 :virtual public A
{
public :
B1()
:b1(2)
{
cout << "B1()" << endl;
}
~B1()
{
cout << "~B1()" << endl;
}
int b1;
};
class B2 : virtual public A
{
public:
B2()
:b2(3)
{
cout << "B2()" << endl;
}
~B2()
{
cout << "~B2()" << endl;
}
int b2;
};
class C : public B1,public B2
{
public:
C()
:c(4)
{
cout << "C()" << endl;
}
~C()
{
cout << "~C()" << endl;
}
int c;
};
此时我们定义一个C的对象,我们计算它的大小发现其为24。因为在B1和B2虚拟继承的时候会产生一个偏移量其大小为4个字节。那么这样我们就知道了为什么C的对象的大小为24。