关于C++多重继承的问题

Question about multi-inheritance in C++?

本文关键字:问题 多重继承 C++ 关于      更新时间:2023-10-16

我有以下代码:

#include "stdafx.h"
#include <iostream>
#include <conio.h>
using namespace std;
#define MNAME 30
class Person {
public:
    char name[MNAME + 1];
};
class Student : public Person {
};
class Staff : public Person {
};
class Faculty : public Student, public Staff {
};
int _tmain(int argc, _TCHAR* argv[])
{
    Faculty faculty;
    cout << "Address of faculty.Person::name: " << &faculty.Person::name << endl;
    cout << "Address of faculty.Student::name: " << &faculty.Student::name << endl;
    cout << "Address of faculty.Staff::name: " << &faculty.Staff::name << endl;
    getch();
    return 0;
}

执行时,程序给出结果:

Address of faculty.Person::name: 0012FF20 // **Line 1**
Address of faculty.Student::name: 0012FF20 // **Line 2**
Address of faculty.Staff::name: 0012FF3F // **Line 3**

我不明白。为什么Line 1Line 2中的地址与Line 3不同,而学生和教职员工都从人那里继承姓名?

当你以这种方式进行多重继承时,你会得到祖父类的两个副本。这是经典的可怕钻石问题,您尝试这样做:

       人      /      \     学生员工       \      /       能力

但是通过正常的继承,你实际上得到了这个:

   人 人      |       |     学生员工       \      /       能力
因此,在

教职员工实例中实际上有 2 个人,这意味着您将获得 2 个名字。

要获得上面第一个图中的钻石,您需要使用虚拟继承。

class Staff : public virtual Person {
};
class Student : public virtual Person {
};

使用常规的多重继承,您可以获得共享基类的多个副本。 如果需要一个副本,请使用虚拟继承。

在维基百科中解释得很好

class Student : public virtual Person {
};
class Staff : public virtual Person {
};

会得到你所期望的

您分别从两个不同的类继承。

应使用虚拟继承

您遇到了经典的钻石继承问题。由于多重继承在C++的工作方式,Faculty中实际上有两个不同的name副本。这通常可以通过使用这样的虚拟继承来解决,因此您只有一个 Person 实例及其成员:

class Student : public virtual Person {
};
class Staff : public virtual Person {
};

我很确定在这种情况下,但是您不想这样做。假设每个Faculty都是StudentStaff成员似乎不合理,因此您不应该以这种方式表示它。Faculty总是一个Staff似乎是合理的,所以你可以使用单一继承来模拟这种关系。然后,如果需要,从学生那里分解出(到自由函数或单独的类中)Faculty中也需要的通用代码。

class Faculty继承了class Person的两个子对象,一个通过class Student,另一个通过class Staff

&faculty.Staff::name 返回通过 class Staff 派生的class Person子对象的地址。

&faculty.Student::name 返回通过 class Student 派生的class Person子对象的地址。

两者都是不同的子对象,因此地址也不同。

对于多重继承,派生类faculty有 2 个Person副本。 第 1 到 Student 和第 2 到 Staff

当您引用faculty.Person::name时,它通过Student或通过Staff引用。这是一个模棱两可的情况,甚至不会用 g++ 编译。

在 MSVC 中,似乎由于Faculty先继承Student,然后继承Staff,因此它将faculty.Person::name称为facutlty ==> Student ==> Person ==> name。这就是为什么前 2 行的输出相同而第 3 行的输出不同。

有点跑题了,但是....大多数有经验的开发人员都避免多重继承。 它难以维护,充满危险。