虚拟继承中构造函数调用的顺序

时间:2012-05-10 12:40:57

标签: c++ constructor virtual-inheritance

class A {
        int i;
public: 
        A() {cout<<"in A's def const\n";};
        A(int k) {cout<<"In A const\n";  i = k; }
        };

class B : virtual public A {
public:
        B(){cout<<"in B's def const\n";};
        B(int i) : A(i) {cout<<"in B const\n";}
        };

class C :   public B {
public:
        C() {cout<<"in C def cstr\n";}
        C(int i) : B(i) {cout<<"in C const\n";}
        };

int main()
{
        C c(2);
        return 0;
}

这种情况下的输出是

in A's def const
in B const
in C const

为什么这不会进入in A const

`它应该遵循1 arg构造函数调用的顺序。 但是使用虚拟关键字从A派生B实际上发生了什么。

还有更多问题

即使我删除了上面程序中的virtual关键字并删除了所有默认构造函数,它也会出错。那么,为什么它需要def构造函数

3 个答案:

答案 0 :(得分:14)

虚拟基类的构造函数总是使用它可能传入的任何参数从最派生类调用。在您的情况下,派生程度最高的类没有为A指定初始化程序,因此默认情况下使用构造函数。

答案 1 :(得分:7)

作为JamesKanze has explained,在virtual继承的情况下,它是调用虚拟基类的构造函数的派生程度最高的类。因此,如果您希望A的构造函数调用一个整数,则需要将其添加到C的初始化列表中。

C(int i) : A(i), B(i) {cout<<"in C const\n";}

对于问题的第二部分,不需要默认构造函数,但是派生类必须显式调用非默认构造函数,因为在没有非默认构造函数的情况下编译器无法为您执行此操作

#include <iostream>
using namespace std;

class A {
  int i;
public:
  // A() {cout<<"in A's def const\n";};
  A(int k) {cout<<"In A const\n";  i = k; }
};

class B : virtual public A {
public:
  // B(){cout<<"in B's def const\n";};
  B(int i) : A(i) {cout<<"in B const\n";}
};

class C :   public B {
public:
  C() : A(42), B(42) {cout<<"in C def cstr\n";}
  C(int i) : A(i), B(i) {cout<<"in C const\n";}
};

int main()
{
  C c(2), c2;
  return 0;
}

打印出来

In A const
in B const
in C const
In A const
in B const
in C def cstr

答案 2 :(得分:2)

这里有两个问题。

  

为什么这不会进入A const?

因为您正在使用虚拟继承。

使用虚拟继承时,Initialization list of most-derived-class's ctor directly invokes the virtual base class's ctor.。在这种情况下,这意味着C的构造函数直接调用A的构造函数 。由于您尚未指定在A的初始化列表中调用哪个C构造函数,因此将调用默认构造函数。

通过将C::C(int)的实施更改为:

来解决此问题
C(int i) : A(i), B(i) {cout<<"in C const\n";}
  

如果我删除上述程序中的虚拟关键字并删除所有   默认构造函数它给出错误。那么,为什么它需要def   构造

由于B也未指定要调用的A ctor,因此使用默认构造函数。如果删除A s defctor,则无法编译B