c ++可以用作虚拟基础的类具有带参数的构造函数吗?

时间:2015-12-08 11:10:09

标签: c++ constructor virtual-inheritance

我是C ++新手,我正在尝试构建一个多继承类,使用一个通用的虚拟继承类(参见下面的代码)。我的书礼貌地忽略的是虚拟继承课程的情况。构造函数有参数。下面的代码是我尝试这样做的。 如果我在两个派生类中删除类库的虚拟继承,则代码构建正常。但是,如果我保持原样,它就不会构建。(在ubuntu下的g ++)

我有几个问题:

1)最重要的是:为什么代码没有建立?

2)虚拟继承类是否具有带参数的构造函数?

3)如果问题2)为真,那么如何评估以下行?

derived(int i,int j, int k):derived1(i,j),derived2(j,k){};

每个派生类都调用基础构造函数,每个构造函数都有第二个参数。但是只有一个副本存在于派生中,因为它作为虚拟继承。我想在这种情况下理解执行哪些基本构造函数以及使用什么参数:j或k? (我不确定这条线是否有效)。

#include <iostream>
using namespace std;

class base
{
int x;
public:
base(int i){cout<<"Constructing base "<<i<<endl;x=i;}
~base(){cout<<"Destructing base"<<endl;}
};

class derived1:virtual public base
{
int x1;
public:
derived1(int i,int j): base(j){cout<<"Constructing derived1 "  <<i<<endl;x1=i;}
~derived1(){cout<<"Destructing derived1"<<endl;}
};

class derived2:virtual public base
{
int x2;
public:
derived2(int i,int j): base(j){cout<<"Constructing derived2 "<<i<<endl;x2=i;}
~derived2(){cout<<"Destructing derived2"<<endl;}
};

class derived:public derived1, public derived2
{
int z;
public:
derived(int i,int j, int k):derived1(i,j),derived2(j,k){cout<<"Constructing derived "<<k<<endl;z=k;}
~derived(){cout<<"Destructing derived"<<endl;}
};

int main()
{
derived ob(2,3,4);
}

2 个答案:

答案 0 :(得分:3)

层次结构中的任何类都可以在其mem-initializer-list(:之后的构造函数定义的一部分)中列出其虚拟基类,但只有其中一个实际执行这些构造函数:派生最多类。

让我们想象一下这样的设置:

#include <iostream>

struct V
{
  explicit V(char c) { std::cout << c << '\n'; }
};

struct A : virtual V
{
  A() : V('a') {}
};

struct B : A, virtual V
{
  B() : V('b') {}
};

struct C : B
{
  C() : V('c') {}
};

int main()
{
  A a; // prints 'a'
  B b; // prints 'b'
  C c; // prints 'c'
}

WhiteSpaces

正如您所看到的,即使所有ABC在其构造函数中初始化V,也只是最派生的类(类型为您实际创建的对象)执行其初始化。

现在让我们假设我们像这样添加一个类D

struct D : C
{
  D() {}
};

这将[Live example] - D在其mem-initializer-list中不列出V,因此将使用默认构造函数,但这不存在。

使用从derivedderived1派生的derived2来解决您的具体示例:在创建derived类型的对象时,derived是派生最多的因此,只有derived本身的构造函数可以将参数传递给base构造函数。在创建base对象时,derived1derived2的构造函数内的derived的任何初始化都将被忽略。

答案 1 :(得分:2)

虚拟基类由大多数派生类的构造函数初始化,即使最派生类不直接从它们继承。

这意味着如果您的类层次结构包含任何需要构造函数参数的虚拟基类,则派生程度最高的类构造函数必须在其 mem-initializer-list 中命名它们并提供任何所需的参数。点。由于虚拟基类是在任何非虚基类之前初始化的,因此建议将它们放在初始化列表中的非虚基类之前:

derived(int i, int j, int k)
    : base(i)     // note: derived does not inherit directly from base
    , derived1(i, j)
    , derived2(j, k)
{
    cout << "Constructing derived " << k << endl;
    z = k;
}

这也意味着如果派生类依赖于传递给虚拟基础的特定参数,则应将其标记为final,以使其不能继承;否则,任何继承类都可以传递“错误”参数。

另请注意,derived1derived2必须为base提供构造函数参数,即使它们永远不会被使用。这是该语言中的一个小错误,但没有人打扰它(DR257通过https://stackoverflow.com/a/32214536/567292