先看代码:
#includeusing namespace std; class Person // 基类 { protected: int age; }; class Student : public Person // 派生类 { }; class Teacher: public Person // 派生类 { }; class AssiTeacher : public Student, public Teacher // 最远派生类 { }; int main() { AssiTeacher a; a.age = 25; }
菱形问题对这个例子来说就是:你想要通过AssiStudent实例访问Person::age,将导致编译错误。
a.age 是模糊的(ambigous),因为编译器不知道你是要问:Student::Person::age 还是Teacher::Person::age,造成了二义性。
如果你愿意,你甚至可以分别设置他们:
Student::Person::var =25; Teacher::Person::a = 26;
这显然是不合理的,因为助教AssiTeacher显然只需要一个age属性
为什么会造成这样的问题?我们来看创建对象a时,对各个类的构造过程:
我们可以看到,按基类先构造原则,编译器通过分别调用Teacher和Student的构造函数,将Person类构造了两次,造成了重复。我们知道,在编程中,只要出现了重复那必然伴随着错误。要避免错误,我们就要消除掉对Person类的重复构造。
如果派生类可能被用作基类,为了防止出现二义性,在派生类derive从基类Base继承时 选择虚继承。
若派生类Derive 不作基类使用,最好加上 final禁止继承
注意看代码注释
#include#include using namespace std; class Person { public: Person(string inName, int inAge):name(inName),age(inAge) { cout << "construct Person" << endl; } void display() { cout << name < public: Student(string inName, int inAge,string inId,string inScore):Person(inName,inAge),id(inId),score(inScore) // 这里不会执行Person基类的构造函数 { cout << "construct Student" << endl; } void display() { Person::display(); cout << id << endl; cout << score << endl; } protected: string id, score; }; class Teacher : virtual public Person //虚基类,避免对基类的重复构造引发菱形问题 { public: Teacher(string inName, int inAge,string inDepart,float inSalary):Person(inName, inAge),department(inDepart),salary(inSalary) // 这里不会执行Person基类的构造函数 { cout << "construct Teacher" << endl; } void display() { Person::display(); cout << department << endl; cout << salary << endl; } private: string department; float salary; }; class AssiTeacher final:public Teacher, public Student // 最派生类 { public: AssiTeacher(string inName, int inAge, string inId, string inScore,string inDepart, float inSalary) :Person(inName,inAge), Student(inName, inAge, inId , inScore), Teacher(inName, inAge, inDepart, inSalary) //在最派生类(AssiTeacher)中不仅要对直接基类进行初始化,还要负责对虚基类初始化。 // 在这里构造Person,Student,Teacher { cout << "constructed AssiTeacher" << endl; } void display() { Teacher::display(); Student::display(); } }; int main() { AssiTeacher a("通辽可汗", 25, "20220427", "97", "teacher", 3000.0); a.display(); return 0; }
此时的构造顺序为:至此,解决了重复构造Person类的问题,菱形问题解决



