c++ - 使用具有虚拟多重继承的基本构造函数

标签 c++ c++11 virtual-inheritance

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

B int v

D

取而代之的是,E 的构造函数调用 B 的默认构造函数,结果是:

B

D

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

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

#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(请参阅注释代码)。

正如 Eljay 首先正确评论的那样,我假设错误地使用了“using D::D”。 “using”关键字从不重新定义 E 的构造函数,这与 D 的构造函数类似;它只是调用基类D的构造函数,并强制构造基类D。后一个事实触发了虚拟基类构造的层次结构(正如 StoryTeller 在下面回复的那样)并导致我的问题根据需要构造 E 类的对象。

最佳答案

这是一个相当普遍的陷阱。首先让我说 A 的存在是一个转移注意力的问题。您可以通过完全省略示例来缩短示例。

您没有看到使用 B(int) 的原因是 C++ 标准中的两个子句。第一[class.inhctor]/8说:

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 继承的 c'tor 被翻译成这样:

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

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

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

  • 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 能够并且将会初始化虚拟基。派生最多的 c'tor 是如何做到这一点的?正如我们之前所写。它从其成员初始值设定项列表中省略了虚拟基础。所以虚拟基是默认初始化的

如果你想传递一个整数给B的c'tor。你需要自己定义E的构造函数:

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

关于c++ - 使用具有虚拟多重继承的基本构造函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/47980682/

相关文章:

c++ - 嵌入式 Lua 和重载的 C++ 运算符

c++ - 使用私有(private)继承时,以何种方式继承基础构造函数?

c++ - 有没有办法在编译时检查 std::initializer_list 参数的数量?

c++ - 虚拟继承困惑

c++ - 为什么 gcc 不支持裸函数?

c++ - make/gmake 的条件依赖

c++ - 程序不显示显示处理和计时的窗口

c++ - 如何使用枚举将 char 值映射到 int

C++ 虚拟继承 : static_cast "this" to virtual parent in initializer list of derived

c++ - 多重或虚拟继承下的类的内存布局和vtable(s)?