8

我有以下代码:

#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,而 Student 和 Staff 都从 Person 继承名称?

4

7 回答 7

13

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

        人
       / \
     学生工作人员
       \ /
        学院

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

    人 人
      | |
     学生工作人员
       \ /
        学院

因此,在 Faculty 的实例中确实有 2 个 Person,这意味着您将获得 2 个名称。

要获得上面第一张图中的菱形,您需要使用虚拟继承

class Staff : public virtual Person {
};
class Student : public virtual Person {
};
于 2011-05-18T11:50:58.973 回答
9

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

维基百科解释得很好

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

会得到你所期望的

于 2011-05-18T11:49:05.773 回答
2

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

你应该使用虚拟继承

于 2011-05-18T11:49:51.437 回答
1

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

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

在这种情况下,我很确定,但是您不想这样做。假设 everyFaculty也是StudentANDStaff成员似乎不合理,因此您不应该以这种方式表示它。Facultya总是 a似乎是合理的Staff,因此您可以使用单继承来建模这种关系。然后,如果需要,将Faculty.

于 2011-05-18T13:30:14.197 回答
0

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

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

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

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

于 2011-05-18T11:48:57.053 回答
0

对于多重继承,您的派生类faculty有 2 个Person. 第 1 到Student第 2 到Staff.

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

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

于 2011-05-18T12:00:03.677 回答
0

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

于 2011-05-18T12:03:46.650 回答