用作虚拟基的c++can类具有带参数的构造函数

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

本文关键字:参数 构造函数 c++can 虚拟      更新时间:2023-10-16

我是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);
}

层次结构中的任何类都可以在其mem初始值设定项列表(:之后的构造函数定义部分)中列出其虚拟基类,但它们中只有一个会实际执行这些构造函数:最派生的类。

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

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

【实例】

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

现在,让我们假设我们添加一个类D,如下所示:

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

这不会编译—D没有在其mem初始值设定项列表中列出V,因此将使用默认构造函数,但这并不存在。


用从derived1derived2派生的derived来说明您的具体示例:当创建类型为derived的对象时,derived是派生最多的类型,因此只有derived本身的构造函数才能将参数传递给base构造函数。在创建derived对象时,derived1derived2的构造函数内对base的任何初始化都将被简单地忽略。

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

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

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)