欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

C++菱形继承和虚继承

程序员文章站 2024-01-01 17:41:52
...

1、多个对象之间的继承关系

1)单继承

class Person
{
public:
    string _name;
};

class Student : public Person
{
protected:
    int _num;
};

class Graduate : public Student
{
protected:
    int _id;
};

C++菱形继承和虚继承

2)多重继承

class Person
{
public:
    string _name;
};

class Student : public Person
{
protected:
    int _num;
};

class Graduate : public Person
{
protected:
    int _id;
};

C++菱形继承和虚继承

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;
}

C++菱形继承和虚继承

菱形继承的问题是会出现数据的二义性和冗余。如上例,Student中有一份Person的_name,Graduate中也有一份Person的_name,当Assistant继承了Student和Graduate之后,Assistant中会有两份Person的_name

C++菱形继承和虚继承

2、解决方案

1)指定作用域

可以用指定作用域的方式进行访问,但是这样的话,修改了Student中的name,并不会修改Teacher中的name,这样就难免造成歧义

a1.Student::_name = "Tom";
a1.Teacher::_name = "Jack";

C++菱形继承和虚继承

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;
}

C++菱形继承和虚继承

C++菱形继承和虚继承

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的对象模型发生了变化
没有虚继承的大小
C++菱形继承和虚继承

有虚继承的大小
C++菱形继承和虚继承

2)对象模型&&虚基表

显而易见,没有虚继承的时候,对象模型是这样的
C++菱形继承和虚继承

但是我们用了虚继承的时候,他的对象模型,需要通过内存窗口观察。
C++菱形继承和虚继承

通过观察,不难发现,没有虚继承的时候,a1的空间大小是20;用了虚继承之后,a1的空间大小是24。

Assistant a1;
a1.Student::_age = 20;
a1.Teacher::_age = 16;

执行这两句代码,对Student的_age和Teacher的_age进行赋值。发现修改的是同一块空间,这说明了虚继承的两个类,共用的是同一个成员函数,这样很好的解决了数据的二义性和冗余的问题。
C++菱形继承和虚继承

4、虚继承的缺点

1、结构复杂,他在对象空间中放置了虚基表的地址,同时还开辟了虚基表的空间
2、效率稍微降低,因为需要对虚基表的地址多一次的解引用。

上一篇:

下一篇: