关于 C++ 中多重继承的问题?
我有以下代码:
#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
不同,而Student和Staff都从Person继承名称?
I have the following code:
#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;
}
When executed, the program gives the results:
Address of faculty.Person::name: 0012FF20 // **Line 1**
Address of faculty.Student::name: 0012FF20 // **Line 2**
Address of faculty.Staff::name: 0012FF3F // **Line 3**
I don't get it. Why the address in Line 1
and Line 2
is different from Line 3
, while both Student and Staff inherits name from Person?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(7)
有点偏离主题,但是......大多数有经验的开发人员都会避免多重继承。它很难维护并且充满危险。
A bit off topic but....Most experienced developers avoid multiple inheritance. It is difficult to maintain and fraught with peril.
classFaculty
继承了classPerson
的两个子对象,一个通过classStudent
继承,另一个通过classStaff
继承。&faculty.Staff::name
返回通过class Staff
派生的class Person
的子对象的地址。&faculty.Student::name
返回通过class Student
派生的class Person
的子对象的地址。两者都是不同的子对象,因此地址也不同。
class Faculty
inherits two sub objects ofclass Person
, one throughclass Student
and another throughclass Staff
.&faculty.Staff::name
returns address of the sub object ofclass Person
derived throughclass Staff
.&faculty.Student::name
returns address of the sub object ofclass Person
derived throughclass Student
.Both are different sub objects and hence the different address.
对于多重继承,您的派生类
faculty
有2个Person
副本。第一名至学生
,第二名至员工
。当您引用
faculty.Person::name
时,它是通过Student
或通过Staff
引用的。这是一种不明确的情况,甚至无法用g++编译。在MSVC中,似乎由于
Faculty
首先继承Student
,然后继承Staff
,所以它引用了faculty.Person::name
> 作为功能==>学生==>人物==>名称
。这就是为什么前两行的输出相同而第三行的输出不同。For multiple inheritance your derived class
faculty
has 2 copies ofPerson
. 1st throughStudent
and 2nd throughStaff
.When you refer
faculty.Person::name
, it refers either viaStudent
or viaStaff
. This is an ambiguous situation and even will not compile with g++.In MSVC, it seems that since
Faculty
inheritsStudent
first and thenStaff
, it's referringfaculty.Person::name
asfacutlty ==> Student ==> Person ==> name
. That's why output of first 2 lines are same and 3rd line is different.您分别从两个不同的类继承。
你应该使用虚拟继承
you are inheriting from the two different classes separately.
you should use virtual inheritance
您遇到了经典的钻石继承问题。由于 C++ 中多重继承的工作方式,
Faculty
中实际上有 两个 个不同的name
副本。这通常可以通过使用像这样的虚拟继承来解决,因此您只有一个Person
及其成员的实例:我很确定在这种情况下,但您不想这样做。假设每个
Faculty
同时也是Student
和Staff
成员似乎并不合理,因此您不应该在此表示它方式。Faculty
似乎总是Staff
,因此您可以使用单一继承来建模该关系。然后,如果需要,从学生中提取出(分解为自由函数或单独的类)Faculty
中也需要的通用代码。You've encountered the classic diamond inheritance problem. Due to the way multiple inheritance work in C++ there are actually two distinct copies of
name
inFaculty
. This can typically be solved by using virtual inheritance like this, so you only have one instance ofPerson
and its members:I'm pretty sure in this case however you don't want to do this. It doesn't seem reasonable to assume that every
Faculty
is also aStudent
AND aStaff
member, so you shouldn't represent it in this way. It seems plausible that aFaculty
would always be aStaff
, so you could use single inheritance to model that relationship. Then if needed, factor out (into free functions or a separate class) the common code from student that's also needed inFaculty
.通过常规多重继承,您可以获得共享基类的多个副本。如果您想要一份副本,请使用虚拟继承。
Wikipedia 中有很好的解释
会给你你所期望的
With regular multiple inheritance you get multiple copies of shared base classes. If you want one copy, use virtual inheritance.
Explained well in Wikipedia
Will get you what you expected
当您以这种方式进行多重继承时,您将获得祖父母类的两个副本。这是经典的可怕的钻石问题,其中你尝试这样做:
但是通过正常的继承,你实际上得到了这个:
所以在Faculty的实例中确实有2个Person,这意味着你会得到2个名字。
要获得上面第一个图中的菱形,您需要使用 虚拟继承。
When you do multiple inheritance this way you get two copies of the grandparent class. This is the classic dreaded diamond problem, where you try to do this:
but through normal inheritance you actually get this:
So there's really 2 Person's in an instance of Faculty, meaning youll get 2 names.
To get the diamond in the first diagram above, you want to use virtual inheritance.