Question about multin inheritance in C ++?
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 do not understand. Why is the address in Line 1 and Line 2 different from Line 3 , and both Student and Staff inherit the name from Person?
With regular multiple inheritance, you get multiple copies of the common base classes. If you need one copy, use virtual inheritance.
Well explained on Wikipedia
class Student : public virtual Person { }; class Staff : public virtual Person { }; You will get what you expected
When you do multiple inheritance, you get two copies of the grandparent class. This is a classic dreaded diamond problem where you are trying to do this:
Person
/ \
Student staff
\ /
Faculty
but through regular inheritance, you really get this:
Person person
| |
Student staff
\ /
Faculty
So, there really are 2 people in the copy of the faculty, that is, you will get 2 names.
To get the diamond in the first diagram above, you want to use virtual inheritance .
class Staff : public virtual Person { }; class Student : public virtual Person { }; you inherit from two different classes separately.
you must use virtual inheritance
You are faced with the problem of classic diamond inheritance. Due to how many inheritances work in C ++, there are actually two different copies of name in Faculty . You can usually solve this using virtual inheritance like this, so you only have one instance of Person and its members:
class Student : public virtual Person { }; class Staff : public virtual Person { }; I am sure of this, but you do not want to do this. It seems reasonable to assume that each Faculty also a member of Student AND a Staff , so you should not represent it that way. It seems plausible that Faculty will always be Staff , so you can use single inheritance to model this relationship. Then, if necessary, discard (in free functions or a separate class) the general code from the student, which is also necessary at the Faculty .
class Faculty inherits two subclasses of class Person , one through class Student and the other through class Staff .
&faculty.Staff::name returns the address of the helper class Person object obtained through class Staff .
&faculty.Student::name returns the address of the class Person sub-object obtained through class Student .
Both are different subordinate objects and therefore different addresses.
For multiple inheritance, the faculty derived class has 2 copies of Person . 1 to Student and 2 to Staff .
When you refer to faculty.Person::name , it means either through Student or through Staff . This situation is ambiguous and will not even compile with g ++.
In MSVC, it seems that since faculty first inherits Student and then Staff , it refers to faculty.Person::name as facutlty ==> Student ==> Person ==> name . Therefore, the output of the first two lines is the same, and the third line is different.
A little off topic, but .... Most experienced developers avoid multiple inheritance. Difficult to maintain and fraught with danger.