c++ - 两个父类的构造函数的顺序

标签 c++ inheritance multiple-inheritance virtual-inheritance

我对两个版本的代码有一个疑问。
唯一的不同是在父类之间切换虚拟关键字。
有什么原因会发生这种情况吗?
版本一:

#include<iostream> 
using namespace std; 
class Person { 
public: 
    Person(int x) { cout << "Person::Person(int ) called" << endl; } 
    Person()     { cout << "Person::Person() called" << endl; } 
}; 

class Faculty : public Person { 
public: 
    Faculty(int x):Person(x) { 
    cout<<"Faculty::Faculty(int ) called"<< endl; 
    } 
}; 

class Student : virtual public Person { 
public: 
    Student(int x):Person(x) { 
        cout<<"Student::Student(int ) called"<< endl; 
    } 
}; 

class TA : public Faculty, public Student { 
public: 
    TA(int x):Student(x), Faculty(x), Person(x) { 
        cout<<"TA::TA(int ) called"<< endl; 
    } 
}; 

int main() { 
    TA ta1(30); 
} 
版本的输出:
Person::Person(int)被称为
Person::Person(int)被称为
Faculty::Faculty(int)被称为
学生::学生(int)叫
TA::TA(int)称为

第二版:
#include<iostream> 
using namespace std; 
class Person { 
public: 
    Person(int x) { cout << "Person::Person(int ) called" << endl; } 
    Person()     { cout << "Person::Person() called" << endl; } 
}; 

class Faculty : virtual public Person { 
public: 
    Faculty(int x):Person(x) { 
    cout<<"Faculty::Faculty(int ) called"<< endl; 
    } 
}; 

class Student :  public Person { 
public: 
    Student(int x):Person(x) { 
        cout<<"Student::Student(int ) called"<< endl; 
    } 
}; 

class TA : public Faculty, public Student { 
public: 
    TA(int x):Student(x), Faculty(x), Person(x) { 
        cout<<"TA::TA(int ) called"<< endl; 
    } 
}; 

int main() { 
    TA ta1(30); 
} 
输出为:
Person::Person(int)被称为
Faculty::Faculty(int)被称为
Person::Person(int)被称为
学生::学生(int)叫
TA::TA(int)称为

最佳答案

类的初始化顺序基于在类的基类说明符列表中声明的顺序:

  • 如果这是派生最多的类,则将初始化虚拟基类。它们的初始化顺序基于对该类的基类说明符列表的深度优先的从左到右搜索。
  • 非虚拟基类从左到右初始化
  • 此类的成员根据声明顺序
  • 构造
  • 此类的构造函数体运行

  • 对于每个初始化的对象,此过程将递归重复。

    对于第一个示例:
  • TA是派生最多的类,因此首先初始化其Person虚拟基础对象。
  • Person的构造函数主体运行并打印其消息。

  • Faculty是第一个声明的基类,因此接下来对其进行初始化。
  • Faculty具有一个非虚拟基类Person,因此它初始化了自己的Person子对象。
  • Person的构造函数主体运行并打印其消息

  • Faculty的构造函数主体运行并打印其消息

  • Student是下一个基类,因此接下来将对其进行初始化。
  • Student不是派生最多的类,因此它没有获得自己的Person子对象进行初始化。
  • Student的构造函数主体运行并打印其消息

  • TA的构造函数主体运行并打印其消息

  • 结果是,构造函数的主体按以下顺序执行:
  • Person
  • Person
  • Faculty
  • Student
  • TA

  • 对于第二个示例:
  • TA是派生最多的类,因此首先初始化其Person虚拟基础对象。
  • Person的构造函数主体运行并打印其消息。

  • Faculty是第一个声明的基类,因此接下来对其进行初始化。
  • Faculty不是派生最多的类,因此它没有获得自己的Person子对象进行初始化。
  • Faculty的构造函数主体运行并打印其消息

  • Student是下一个基类,因此接下来将对其进行初始化。
  • Student具有一个非虚拟基类Person,因此它初始化了自己的Person子对象。
  • Person的构造函数主体运行并打印其消息

  • Student的构造函数主体运行并打印其消息

  • TA的构造函数主体运行并打印其消息

  • 结果是,构造函数的主体按以下顺序执行:
  • Person
  • Faculty
  • Person
  • Student
  • TA

  • 请注意,在两种情况下,都有两个Person子对象。为了使FacultyStudent共享一个Person子对象,两者都必须从Person继承,即:
    class Person {
    public:
        Person(int x) { cout << "Person::Person(int) called" << endl; }
        Person()      { cout << "Person::Person() called" << endl; }
    };
    
    class Faculty : virtual public Person {
    public:
        Faculty(int x) : Person(x) {
            cout<<"Faculty::Faculty(int) called"<< endl;
        }
    };
    
    class Student : virtual public Person {
    public:
        Student(int x) : Person(x) {
            cout<<"Student::Student(int) called"<< endl;
        }
    };
    
    class TA : public Faculty, public Student {
    public:
        TA(int x) : Student(x), Faculty(x), Person(x) {
            cout<<"TA::TA(int) called"<< endl;
        }
    };
    
    在这种情况下,逻辑将是:
  • TA是派生程度最高的类,因此其Person虚拟基础对象首先被初始化。
  • Person的构造函数主体运行并打印其消息。

  • Faculty是第一个声明的基类,因此接下来对其进行初始化。
  • Faculty不是派生最多的类,因此它没有获得自己的Person子对象进行初始化。
  • Faculty的构造函数主体运行并打印其消息

  • Student是下一个基类,因此接下来将对其进行初始化。
  • Student不是派生最多的类,因此它没有获得自己的Person子对象进行初始化。
  • Student的构造函数主体运行并打印其消息

  • TA的构造函数主体运行并打印其消息

  • 结果是类的构造函数体按以下顺序执行:
  • Person
  • Faculty
  • Student
  • TA
  • 关于c++ - 两个父类的构造函数的顺序,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62557119/

    相关文章:

    c++ - 在哪里 Hook 编码约定脚本?

    c++ - C++中具有默认参数的函数指针

    c++ - 了解虚拟基类和构造函数调用

    c++ - 这是对类(Class)友情的恰当运用吗?

    c++ - 在 C+ +'s Eigen library, how do I solve: invalid use of incomplete type ‘const class Eigen::MatrixSquareRootReturnValue<Eigen::Matrix<float, -1, -1>>’

    java - java中如何定义子类(基本继承)

    c++ - 继承比较运算符而不能相互比较派生类

    c++ - 如果继承,则无法使用初始化列表初始化结构?

    c# - 寻找需要多个接口(interface)继承(而不是实现)的示例/案例

    common-lisp - 此 CLOS 代码是否会导致 Common Lisp 中出现运行时或编译时错误?