【问题标题】:In multiple inheritance ( diamond shape), grand parent's default constructor called [closed]在多重继承(菱形)中,祖父母的默认构造函数称为 [关闭]
【发布时间】:2012-09-23 06:24:42
【问题描述】:
#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);
}

O/p:

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

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

【问题讨论】:

  • 虚拟继承在哪里?
  • 因为越来越多的人要求解决方案;没有帮助,这是我的猜测。
  • 除了已经提到的缺少 virtual 关键字之外,输出不可能包含“Person::Person() called”,因为您的代码不包含任何可能打印该字符串的代码.确保代码确实符合您的问题。

标签: c++ constructor multiple-inheritance default-constructor


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    Diamond 配置需要虚拟基类,否则您将在对象表示中获得重复性。

    class A
    {
    }
    
    class B : virtual public A
    {
    };
    
    class C : virtual public A
    {
    }
    
    class D: public B, public C
    {
    }
    

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

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

    【讨论】:

    • OP 声称正在这样做,并且似乎对 A 的构造函数被调用感到惊讶。
    • 是的,我知道有人说他们在俄克拉荷马州的 K-mart 看到了猫王,但这并不意味着他们看到了。他没有将它们声明为虚拟的证据就在 he 发布的代码中,那么你还能做什么呢?
    • 我知道,这涉及到一些猜测。据称A 构造函数只被调用一次,这与虚拟继承兼容。
    【解决方案3】:

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

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

    大部分派生类的ctor初始化列表直接调用虚基类的ctor。

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

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

    但是,如果虚拟基类的作者遵循上一个常见问题解答中的指南,那么虚拟基类的构造函数可能不带参数,因为它没有任何要初始化的数据。这意味着(幸运的是!)最终从虚拟基类继承的具体类的作者无需担心将额外参数传递给虚拟基类的 ctor。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-12-05
      • 2016-03-24
      • 1970-01-01
      • 2013-07-05
      • 1970-01-01
      相关资源
      最近更新 更多