1、多个对象之间的继承关系
1)单继承
class Person
{
public:
string _name;
};
class Student : public Person
{
protected:
int _num;
};
class Graduate : public Student
{
protected:
int _id;
};
2)多重继承
class Person
{
public:
string _name;
};
class Student : public Person
{
protected:
int _num;
};
class Graduate : public Person
{
protected:
int _id;
};
3)菱形继承
class Person
{
public:
string _name;
};
class Student : public Person
{
protected:
int _num;
};
class Teacher : public Person
{
protected:
int _id;
};
class Assistant : public Student, public Teacher
{
protected:
string _majorcoures;
};
int main()
{
Assistant a1;
return 0;
}
菱形继承的问题是会出现数据的二义性和冗余。如上例,Student中有一份Person的_name
,Graduate中也有一份Person的_name
,当Assistant继承了Student和Graduate之后,Assistant中会有两份Person的_name
。
2、解决方案
1)指定作用域
可以用指定作用域的方式进行访问,但是这样的话,修改了Student中的name,并不会修改Teacher中的name,这样就难免造成歧义
a1.Student::_name = "Tom";
a1.Teacher::_name = "Jack";
2)虚继承
通过定义虚继承,我们就可用解决二义性的问题。Student、Teacher、Assistant共用一个Person中的_name。在Student、Teacher继承的Person的时候加上virtual关键字即可。
class Student : virtual public Person
{
protected:
int _num;
};
class Teacher : virtual public Person
{
protected:
int _id;
};
int main()
{
Assistant a1;
//不需要定义指定域
a1._name = "Tom";
a1._name = "Jack";
return 0;
}
3、探讨虚继承函数的对象模型
为了计算大小显而易见,我们将类中的所有成员都定义成整型。
为了访问成员,我们将所有的成员限定符置成public
class Person
{
public:
int _age;
};
//
//class Student : public Person
//{
//protected:
// int _num;
//};
//
//class Teacher : public Person
//{
//protected:
// int _id;
//};
class Student : virtual public Person
{
public :
int _num;
};
class Teacher : virtual public Person
{
public:
int _id;
};
class Assistant : public Student, public Teacher
{
public:
int _year;
};
int main()
{
//a1._name = "Tom";
//a1._name = "Jack";
Assistant a1;
a1._age = 20;
a1._num = 10;
a1._id = 30;
a1._year = 2;
return 0;
}
1)计算大小
当我们使用了虚继承的时候,a1的对象模型发生了变化
没有虚继承的大小
有虚继承的大小
2)对象模型&&虚基表
显而易见,没有虚继承的时候,对象模型是这样的
但是我们用了虚继承的时候,他的对象模型,需要通过内存窗口观察。
通过观察,不难发现,没有虚继承的时候,a1的空间大小是20;用了虚继承之后,a1的空间大小是24。
Assistant a1;
a1.Student::_age = 20;
a1.Teacher::_age = 16;
执行这两句代码,对Student的_age
和Teacher的_age
进行赋值。发现修改的是同一块空间,这说明了虚继承的两个类,共用的是同一个成员函数,这样很好的解决了数据的二义性和冗余的问题。
4、虚继承的缺点
1、结构复杂,他在对象空间中放置了虚基表的地址,同时还开辟了虚基表的空间
2、效率稍微降低,因为需要对虚基表的地址多一次的解引用。