-5
#include<iostream>
using namespace std;
class Person {
   // Data members of person
public:
    Person(int x)  { cout << "Person::Person(int ) called" << endl;   }
};

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() called
Faculty::Faculty(int ) called
Student::Student(int ) called
TA::TA(int ) called

在上面的菱形中,两个父类是用 virtual 关键字从祖父继承的,因此 Person 类的构造函数只被调用一次。但是为什么祖父母的默认构造函数在这里调用。谁能告诉我确切的原因非常感谢

4

3 回答 3

2

TA是 a ,因此调用 ' 的构造函数并Person没有什么意外。如果您像声称的那样使用虚拟继承,那么您的类将有一个子对象,因此它的构造函数被调用一次这一事实是可以预料的。如果您没有使用虚拟继承,则会有两个子对象,并且您可能会期望两个构造函数调用。PersonTAPersonTAPersonPerson

于 2012-09-23T06:30:54.310 回答
1

菱形配置需要虚拟基类,否则您将在对象表示中得到重复。

class A
{
}

class B : virtual public A
{
};

class C : virtual public A
{
}

class D: public B, public C
{
}

这将确保只有一个 A 的表示形式使其成为 D 类型的最终对象,并且它将被所有人共享。

我把它作为一个练习留给提问者如何通过这个来传递构造函数参数。它并不直观,但 google +“虚拟基类”将不仅仅是启发性的。

于 2012-09-23T06:34:02.440 回答
0

C++ Faq很好地回答了你的问题:

[25.12] 当我从使用虚拟继承的类继承时,我需要了解哪些特殊注意事项?

大多数派生类的ctor的初始化列表直接调用虚拟基类的ctor。

因为一个虚拟基类子对象在一个实例中只出现一次,所以有一些特殊的规则可以确保每个实例只调用一次虚拟基类的构造函数和析构函数。C++ 规则说,虚拟基类是在所有非虚拟基类之前构造的。作为程序员,你需要知道的是:类继承层次结构中任何位置的虚拟基类的构造函数都由“最派生”类的构造函数调用。

实际上,这意味着当您创建具有虚拟基类的具体类时,您必须准备好传递调用虚拟基类的构造函数所需的任何参数。而且,当然,如果在您的类祖先中的任何地方都有多个虚拟基类,您必须准备好调用它们的所有构造函数。这可能意味着派生最多的类的构造函数需要比您想象的更多的参数。

但是,如果虚拟基类的作者遵循前面的 FAQ 中的指导,那么虚拟基类的构造函数可能不带任何参数,因为它没有任何要初始化的数据。这意味着(幸运的是!)最终从虚拟基类继承的具体类的作者不必担心将额外的参数传递给虚拟基类的 ctor。

于 2012-09-23T06:35:38.283 回答