为什么派生 class 可以调用基 class 构造函数两次?

Why can a derived class call base class constructor twice?

我正在学习多重继承和菱形问题,但我很困惑为什么一个基础 class 构造函数可以被调用两次而不会首先出现编译器错误。

示例来自 https://www.geeksforgeeks.org/multiple-inheritance-in-c/

#include<iostream> 
using namespace std; 

class Person { 
   // Data members of person  
public: 
    Person(int x)  { cout << "Person::Person(int ) called" << endl;   } 
    int y;                                                               \ <- I added this
}; 

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

class Student : public Person { 
   // data members of Student 
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)   { 
        cout<<"TA::TA(int ) called"<< endl; 
    } 
}; 

int main()  { 
    TA ta1(30); 
} 

输出:

Person::Person(int ) called
Faculty::Faculty(int ) called
Person::Person(int ) called
Student::Student(int ) called
TA::TA(int ) called

由于派生的 class TA 两次调用 Person 构造函数,这是否意味着 TA 将具有两个具有相同名称的数据成员副本,例如 int y?

的两个实例

不打印整数参数,而是尝试打印成员变量的地址。然后用虚拟继承试试,它应该能更好地了解发生了什么。

std::cout << &y << std::endl;

来自 link 的绘图具有误导性,它不是钻石,而是 Y:

 ----------    ----------
|  Person  |  |  Person  |
 ----------    ----------
      ^             ^
      |             |
 ----------    ----------
|  Student |  |  Faculty |
 ----------    ----------
      ^             ^
      |             |
       \-----   ----/
             \ /
              |
         ----------
        |    TA    |
         ----------

是的,您有两个 Person 成员的副本(Student::yFaculty::y)。

通过虚拟继承,您拥有的钻石只有一个唯一 Person

尝试调查您实例化的 TA 对象的大小。尺寸告诉你什么?对于单个 Person 副本,您期望的大小是多少?两份?

尝试实际访问 y 属性,看看是否出现编译错误!