在之前的博客里面,我总结了继承的规则及派生类的成员函数,具体参考这篇博客,https://blog.csdn.net/lvxin15353715790/article/details/82774337
在这篇博客中,我总结一下单继承、多继承以及菱形继承的一些知识点。
单继承–一个子类中只有一个直接父类时称这个继承关系为单继承
Granduate 只有 Student 一个直接父类
多继承–一个子类有两个或以上直接父类时称这个继承关系为多继承
Assistant 有 Student 和 Teacher两个直接父类
菱形继承
Assistant 继承了Student和Teacher两个类,因为Student和Teacher都继承了Person,所以Assistant的对象中有两份Person成员,所以菱形继承存在二义性和数据冗余的问题。
class person
{
public:
string _name;//姓名
person()
{
cout << "person()" << endl;
}
~person()
{
cout << "~person() " << endl;
}
void display()
{
cout << &_name << endl;
}
};
class student:public person
{
public:
int _num;//学号
student()
{
cout << "student() " << endl;
}
~student()
{
cout << "~student() " << endl;
}
void display1()
{
cout << _num << endl;
}
};
class teacher:public person
{
public:
int _id;//编号
teacher()
{
cout <<"teacher() "<< endl;
}
~teacher()
{
cout << "~teacher() " << endl;
}
void display2()
{
cout << _id << endl;
}
};
class assistant :public student, public teacher
{
public:
string _majorcourse;//主修课程
assistant()
{
cout << "assistant() " << endl;
}
~assistant()
{
cout << "~assistant() " << endl;
}
};
int main()
{
assistant a;
//a._name = "xxx";
a.student::_name = "xxx";
a.teacher::_name = "yyy";
a.teacher::_id = 001;
a.student::_num = 002;
a.assistant::_majorcourse= "数学";
system("pause");
return 0;
}
可以看到菱形继承中,要访问冗余的成员,需要用 :: 来指定访问的是哪个类中的成员,从监视的结果也可以看出,由类来访问成员,可以使两份冗余的成员拥有不同的值。
那么怎么解决菱形继承的二义性和数据冗余的问题呢?
在这里,我们引入虚继承来解决。
虚继承就是在继承前面加virtual关键字,这个继承称为虚继承。
1.虚继承解决了在菱形继承体系里面子类对象包含多分父类对象的数据冗余和浪费空间的问题。
2.虚继承体系看起来很复杂,在实际的应用我们通常不会定义如此复杂的继承体系。一般不到万不得已都不要定义菱形结构的虚继承体系结构,因为使用虚继承解决冗余问题也带来了性能上的损耗。
class A
{
public:
int _a;
};
class B : virtual public A
{
public:
int _b;
};
class C : virtual public A
{
public:
int _c;
};
class D : public B, public C
{
public:
int _d;
};
int main()
{
D d;
d.B::_a = 1;
d.C::_a = 2;
d._b = 3;
d._c = 4;
d._d = 5;
system("pause");
return 0;
}
大致过程为:在创建d的时候,构造函数会产生一个虚基表,虚基表中会存储两个指针,这两个指针指向的是B类中_a相对于B的偏移量、C类中_a相对于C的偏移量。
这两个类中的冗余数据只产生了一次,当需要用到这个数据的时候,则是通过指针所指向的偏移量来找到这份冗余数据。