C++ 为什么需要超类空构造函数,但在可怕的菱形情况下不调用它?

C++ 为什么需要超类空构造函数,但在可怕的菱形情况下不调用它?,c++,inheritance,multiple-inheritance,diamond-problem,C++,Inheritance,Multiple Inheritance,Diamond Problem,我试图实现以下设计,这是一种情况: struct super_base { super_base(int a) { b = a; } int b; }; struct base : virtual super_base {}; struct other_base : virtual super_base {}; struct derived : base, other_base { derived(int a) : super_base{a} {} }; int main()

我试图实现以下设计,这是一种情况:

struct super_base
{
  super_base(int a) { b = a; }
  int b;
};

struct base : virtual super_base
{};

struct other_base : virtual super_base
{};

struct derived : base, other_base
{
  derived(int a) : super_base{a} {}
};

int main() {}
这不管用。上面使用Clang的代码的错误非常严重 善于解释错误:

error: call to implicitly-deleted default constructor of 'base'
  derived(int a) : super_base{a} {}
  ^
note: default constructor of 'base' is implicitly deleted because base
      class 'super_base' has no default constructor
因此,我为
super\u base
添加了一个空构造函数,它可以工作:

#include<iostream>
#include<stdexcept>

struct super_base
{
  super_base() { throw std::logic_error{"Constructor should not be called."}; };
  super_base(int a) { b = a; }
  int b;
};

struct base : virtual super_base
{};

struct other_base : virtual super_base
{};

struct derived : base, other_base
{
  derived(int a) : super_base{a} {}
};

int main() { std::cout << derived(10).b << '\n'; }
#包括
#包括
结构超级库
{
super_base(){throw std::logic_error{“不应调用构造函数。”};};
超基数(inta){b=a;}
int b;
};
结构库:虚拟超级库
{};
结构其他基础:虚拟超级基础
{};
派生结构:基,其他_基
{
派生(inta):超基数{a}{
};
int main(){std::cout
这将尝试创建一些构造函数。它尝试创建的构造函数之一是
base::base()

如果
super\u base
没有
super\u base::super\u base()
,则删除此构造函数

如果我们有
super\u base::super\u base()=default
{}
,那么默认情况下
base::base()
存在,即使您没有
=default

同样的事情也发生在
other_base

您的派生类尝试调用基本对象构造函数,这些构造函数被删除,这会给您一个错误

现在,为什么不调用它呢?当您有一个虚拟基类时,构造函数只被调用一次。调用虚拟基类构造函数的中间类型的调用被忽略

因此我们有
derived()
调用
base()
base()
调用
super\u base()
,但由于虚拟继承,该调用被忽略

derived()
'd调用
super\u base(int)


现在,为什么这些规则?因为C++没有“构造函数”的概念,如果你是这个类的派生类,它显式调用一个特定的基构造函数,那么只能调用它。。虚拟继承的功能并不像您希望的那样全面。

多亏了@Yakk的回答,我现在对这个问题有了更清晰的理解。我认为它来自于编译器阶段的顺序。必须有:(1)首先是一个阶段,选择所有需要的构造函数(如果需要,构建隐式构造函数)(2)然后是一个丢弃不需要的构造函数调用的阶段。这将解释为什么编译器试图构建一个它不需要的构造函数。我不知道编译器在这一点上是否严格遵循C++14标准。有一天我应该深入研究该标准和编译器的代码!
struct base:super_base {}: