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

c++ can classes used as virtual bases have constructors with parameters?

我是 C++ 新手,我正在尝试构建一个多重继承 class,具有一个公共虚拟继承 class(请参阅下面的代码)。我的书礼貌地忽略了 virtual inherited class' 构造函数有参数的情况。下面的代码是我尝试这样做的。 如果我在两个派生 class 中删除 class 基的虚拟继承,则代码构建正常。但是,如果我保持原样,它将无法构建。(ubuntu 下的 g++)

我有几个问题:

1) 最不重要的优先:为什么代码没有构建?

2) 虚继承classes可以有带参数的构造函数吗?

3) 如果问题 2) 为真,那么下面一行是如何求值的?

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

每个派生 class 调用基本构造函数,每个都有第二个参数。但是派生中只有一个基的副本存在,因为它是作为虚拟继承的。我想了解在这种情况下执行了哪些基本构造函数以及使用什么参数: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);
}

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

让我们想象这样的设置:

#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'
}

[Live example]

如您所见,即使所有 ABC 在其构造函数中初始化 V,只有最派生的 class(您实际创建的对象的类型)执行其初始化程序。

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

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

这将 not compileD 不会在其 mem-initializer-list 中列出 V,因此将使用默认构造函数,但它不存在。


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

虚基 class 由 最派生的 class 的构造函数初始化,即使最派生的 class 没有直接继承自他们。

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

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;
}

这也意味着,如果派生 class 依赖于传递给虚拟基础的特定参数,则应将其标记为 final 以便它不能被继承;否则,任何继承 class 都可以传递 "wrong" 参数。

另请注意,derived1derived2 必须为 base 提供构造函数参数,即使它们永远不会被使用。这是语言中的一个小错误,但还没有人费心去清理它 (DR257 via )