使用具有虚拟多重继承的基本构造函数 [英] Using base constructors with virtual multiple inheritance

查看:66
本文介绍了使用具有虚拟多重继承的基本构造函数的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

运行下面的代码,我希望获得以下控制台输出:

Running the code below I am expecting to get the following console output:

B int v

D

相反,E的构造函数正在调用B的默认构造函数,结果是:

Instead of that, the constructor of E is calling the default constructor of B and the result is:

B

D

实现正确构造的一种方法是在E中重新声明D的相同构造函数(即,注释的代码部分),但我仍然希望有一个更好的解决方案.

One way of achieving the correct construction, is to re-declare the same constructors of D in E (i.e. the commented code part), but I still hope for a better solution than that.

准备运行代码,带有-std = c ++ 11标志:

Ready to run code, with -std=c++11 flag:

#include <iostream>

class A {
public:
  virtual void fun() = 0;
  virtual void fun2();
  void fun3();
};

class B : public A {
public:
  B();
  B(int);
  void fun();
  void fun2();
};

class C : virtual public B {
public:
  using B::B;
  void fun();
};

class D : virtual public B {
public:
  D();
  D(int);
  void fun();
};

class E : public C, public D {
public:
  using D::D;
  void fun();
};

void A::fun2() {}
void A::fun3() {}
B::B() { std::cout << "B\n"; }
B::B(int v1) { std::cout << "B int v\n"; }
void B::fun() {}
void B::fun2() {}
void C::fun() {}

D::D() { std::cout << "D\n"; }
D::D(int v1) : B(v1) { std::cout << "D\n"; }
void D::fun() {}

/*E::E(int v1): D::B(v1){  std::cout <<"E\n";}  */ void E::fun() {}

int main() {
  E Eob(1);
  return 0;
}

结论:最终,必须为E定义显式构造函数,并显式调用虚拟基类B(请参见注释的代码段).

Conclusion: Eventually, defining explicit constructor for E, with an explicit call to the virtual base class B (see commented piece of code), is necessary.

当Eljay首先正确地评论时,我以为"using D :: D"的使用是错误的."using"关键字从不重新定义E的构造函数,该构造函数类似于D的构造函数;它仅调用基类D的构造函数,并强制基类D的构造.后一个事实触发了虚拟基类构造的层次结构(如StoryTeller在下面回答),并导致我的问题按需要构造了E类的对象.

As Eljay correctly commented in the very first place, I assumed a wrong use of the "using D::D". The "using" keyword, never redefines constructors for E, which would be similar to that of D; it just calls the constructors of the base class D, and forces the base class D construction. The latter fact, triggers the hierarchy of virtual base classes construction (as StoryTeller replied below) and causes my problems to construct as desired an object of class E.

推荐答案

这是一个相当常见的陷阱.首先,我要说 A 的出现是红色鲱鱼.您可以通过完全省略示例来简化示例.

This is a fairly common pitfall. First let me say that the presence of A is a red herring. You could have made your example shorter by omitting it entirely.

您看不到使用 B(int)的原因是由于C ++标准中的两个子句.首先 [class.inhctor]/8 说:

The reason you don't see B(int) used is due to two clauses in the C++ standard. First [class.inhctor]/8 says:

隐式定义的继承构造函数执行以下操作的集合:用户编写的类的初始化带有mem-initializer-list的该类的内联构造函数只有mem-initializer具有用于命名基础的mem-initializer-id在using-declaration的nested-name-specifier中表示的类以及下面指定的表达式列表,其中函数主体中的复合语句为空([class.base.init]).

An implicitly-defined inheriting constructor performs the set of initializations of the class that would be performed by a user-written inline constructor for that class with a mem-initializer-list whose only mem-initializer has a mem-initializer-id that names the base class denoted in the nested-name-specifier of the using-declaration and an expression-list as specified below, and where the compound-statement in its function body is empty ([class.base.init]).

其中说,从 E 中的 D 继承的代码被翻译成如下形式:

Which says that the c'tor inherited from D in E is translated to something like this:

E::E(int i) : D(i) {}

不幸的是,这是您的问题.因为在咨询 [class.base.init/10] :

And that is unfortunately your problem. Because upon consulting [class.base.init/10]:

在非委托构造函数中,初始化在以下顺序:

In a non-delegating constructor, initialization proceeds in the following order:

  • 首先,并且仅对于派生最多的类([intro.object])而言,虚拟基类按以下顺序初始化它们出现在定向的深度优先的从左到右的遍历中基类的非循环图,其中从左到右"是基类在派生类中的外观基本说明者列表.
  • First, and only for the constructor of the most derived class ([intro.object]), virtual base classes are initialized in the order they appear on a depth-first left-to-right traversal of the directed acyclic graph of base classes, where "left-to-right" is the order of appearance of the base classes in the derived class base-specifier-list.

我们看到(强调我的意思),只有最派生的角色才能并且将初始化虚拟基础.以及最派生的c'tor是如何做到的?如我们先前所写.它从其成员初始化程序列表中省略了虚拟基础.因此,虚拟基础是默认初始化的.

We see (emphasis mine) that it is only the most derived c'tor that can and will initialize the virtual base. And how is the most derived c'tor doing that? As we wrote previously. It omits the virtual base from its member initializer list. So the virtual base is default initialized.

如果要将整数传递给 B 的字符.您需要自己定义 E 的构造函数:

If you want to pass an integer to B's c'tor. You need to define E's constructor yourself:

E::E(int i) : B(i), D(i) {}

这篇关于使用具有虚拟多重继承的基本构造函数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆