菱形继承
因为这种继承形似菱形,因此称之为菱形继承,或者钻石继承。
class Grandfather
{
public:
string First_Name;
private:
string Last_Name;
};
class Father :public Grandfather
{
string Last_Name;
};
class Mother :public Grandfather
{
string Last_Nme;
};
class Son :public Father, public Mother
{
string Last_Name;
};
这里的Son到底跟谁姓,它有两个姓。一个是Father的姓,一个是Mother的姓。所以在给Son.First_Name成员赋值时候必须加限定,否则存在二义性问题。
菱形继承还可能存在数据冗余问题,即在Son类里,有两份First_Name数据,那么我到底是不是需要两份数据呢?如果不需要就显得繁琐冗余,大多数情况不需要的。
菱形虚拟继承
虚继承又称之为菱形虚拟继承。在继承关系前加virtual,Grandfather类被称为虚基类。为了解决菱形继承的二义性与数据冗余问题,引进了虚继承的概念。
方法:class 类名: virtual 继承方式 父类名
class Mother :virtual public Grandfather
class Father :virtual public Grandfather
#define _CRT_SECURE_NO_WARNINGS
#include<iostream>
#include<vector>
using namespace std;
class Grandfather
{
public:
string First_Name;
private:
string Last_Name;
};
class Father :virtual public Grandfather
{
string Last_Name;
};
class Mother : virtual public Grandfather
{
string Last_Nme;
};
class Son :public Father, public Mother
{
string Last_Name;
};
int main()
{
Son s;
s.First_Name = "张";
system("pause");
return 0;
}
上述说明对象s中只存在一个First_Name成员,都是Grandfather中的First_Name成员。
不是表的虚基表----偏移量
那么我们看看下面这段代码
#include<iostream>
#include<string>
using namespace std;
class Grandfather
{
public:
int a;
};
class Father :virtual public Grandfather
{
public:
int b;
};
class Mother :virtual public Grandfather
{
public:
int c;
};
class Son :public Father,public Mother
{
public:
int d;
};
int main()
{
Son s;
s.a = 10;
s.b = 20;
s.c = 30;
s.d = 40;
cout << sizeof(s) << endl;
system("pause");
return 0;
}
上述说明对象s中只存在一个a都是Grandfather中的a。
而程序的结果是:
24
请按任意键继续. . .
那结果为什么会是24,不是应该是16吗?
既然知道了虚基类的偏移量的位置,那么我再打开两个内存看到了这两个偏移量。Father类的虚基类的偏移量是(14)H=(20)D。Mother的虚基类的偏移量是(0c)H=(12)D,20-12=8个字节,而虚基表指针位置Mother-Father=0096FEF0-0096FEE8=8字节。说明这两个虚继类是同一个虚基类就是我们的GrandFather。
很多人说C++语法复杂,其实多继承就是一个体现。有了多继承,就存在菱形继承,有了菱形继承就有菱形虚拟继承,底层实现就很复杂。所以一般不建议设计出多继承,一定不要设计出菱形继承。在复杂度及性能上都有问题。