我有以下代码:
#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 1
和Line 2
中的地址与Line 3
不同,而学生和工作人员都从Person继承了姓名?
答案 0 :(得分:13)
当您以这种方式执行多重继承时,您将获得祖父母类的两个副本。这是典型的dreaded diamond问题,您尝试这样做:
Person / \ Student Staff \ / Faculty
但是通过正常的继承,你实际上得到了这个:
Person Person | | Student Staff \ / Faculty
所以在一个Faculty实例中真的有2个人,这意味着你会得到2个名字。
要获得上面第一个图表中的钻石,您需要使用virtual inheritance。
class Staff : public virtual Person {
};
class Student : public virtual Person {
};
答案 1 :(得分:9)
使用常规多重继承,您可以获得共享基类的多个副本。如果您想要一个副本,请使用虚拟继承。
中解释得很好class Student : public virtual Person {
};
class Staff : public virtual Person {
};
会得到你的预期
答案 2 :(得分:2)
你是分别继承两个不同的类。
你应该使用virtual inheritance
答案 3 :(得分:1)
您遇到了经典的钻石继承问题。由于多重继承在C ++中的工作方式,name
中实际上有{em>两个不同的Faculty
副本。这通常可以通过使用这样的虚拟继承来解决,因此您只有一个Person
实例及其成员:
class Student : public virtual Person {
};
class Staff : public virtual Person {
};
在这种情况下,我很确定你不想这样做。假设每个Faculty
也是Student
和Staff
成员似乎是不合理的,因此您不应该以这种方式表示它。 Faculty
始终是Staff
似乎是合理的,因此您可以使用单继承来建模该关系。然后,如果需要,将Faculty
中也需要的学生公共代码分解(自由函数或单独的类)。
答案 4 :(得分:0)
class Faculty
继承了class Person
的两个子对象,一个到class Student
,另一个到class Staff
。
&faculty.Staff::name
返回通过class Person
派生的class Staff
子对象的地址。
&faculty.Student::name
返回通过class Person
派生的class Student
子对象的地址。
两者都是不同的子对象,因此地址不同。
答案 5 :(得分:0)
对于多重继承,派生类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行不同的原因。
答案 6 :(得分:0)
有点偏离主题但......最有经验的开发人员避免多重继承。很难维持和充满危险。