MSVC下菱形继承代码报Person无默认构造函数编译错误的原因及疑问
问题解答
1. 编译错误原因
报错No default constructor exists for class 'Person'的核心原因是虚继承下的构造函数初始化规则:
Employee和Student都以virtual方式继承Person,而Person仅定义了带参构造函数,没有默认构造函数。Employee(int sal)和Student(int cls)这两个单参数构造函数的初始化列表中,没有显式调用Person的带参构造函数。- 对于虚继承的类构造函数:如果它被用来创建独立对象(比如直接
Employee e(5000);),那么它作为最终派生类,必须初始化虚基类Person;编译器会检查构造函数本身的合法性,即使你实际只在Manager中调用这些构造函数,只要它无法完成虚基类的初始化(既没显式调用带参构造,又没有默认构造可用),就会抛出编译错误。
2. 不添加Person默认构造的解决方案
不需要删除Employee和Student的单参数构造函数,有两种可行方案:
方案一:修改单参数构造函数,显式初始化Person
给Person的构造函数传入合理的默认值,让单参数构造函数能合法初始化虚基类:
class Employee :virtual public Person { int msalary; public: Employee(const std::string& name, int age, int sal) :Person{ name,age }, msalary{ sal }{} // 显式调用Person的带参构造,传入默认值 Employee(int sal): Person{"", 0}, msalary { sal }{} }; class Student : virtual public Person { int mclass; public: Student(const std::string& name, int age, int cls) :Person{ name,age }, mclass{ cls }{} // 显式调用Person的带参构造,传入默认值 Student(int cls) :Person{"", 0}, mclass{ cls } {} };
这样既保留了单参数构造函数,又让它们能合法创建独立对象;同时Manager中调用这些构造函数时,虚基类Person的初始化会以Manager中的代码为准(虚基类仅由最终派生类初始化一次,中间派生类的初始化会被忽略)。
方案二:在Manager中调用Employee和Student的带参构造函数
如果不需要单独创建Employee或Student对象,可以保留它们的单参数构造函数(甚至设为protected避免外部调用),但修改Manager的构造函数,调用Employee和Student中带name、age的构造函数:
class Manager :public Student, Employee { public: Manager(const std::string& name,int age, int salary,int cl) : Person{name,age}, Student{name, age, cl}, Employee{name, age, salary} {} };
此时Employee和Student的带参构造函数中对Person的初始化会被忽略,最终由Manager完成虚基类的初始化。如果不需要单参数构造函数,也可以直接删除它们,简化代码。
内容的提问来源于stack exchange,提问作者lorem1213
相关产品推荐
相关产品推荐

