c++ - 为什么使用声明的继承构造函数不使用默认构造函数初始化虚拟基类?

标签 c++ multiple-inheritance virtual-inheritance using-declaration

昨天我偶然发现了一个使用声明的继承构造函数的question。在仔细阅读答案和linked standard draft N3337之后,我发现当直接基类也使用using从虚拟基继承构造函数时,可能存在一些不一致(或至少是我的误解)。

这是一个例子:

struct A
{
    A(int, int){}
};

struct B : virtual A
{
    using A::A;
};

struct C : virtual A
{
    using A::A;
};

struct BC : B, C
{
    using B::B;
    using C::C;
}; 

// Now if we define an inline constructor that does the same
// as the constructor B inherited...
struct BB : virtual A
{
    BB(int a, int b):A(a,b){}
};

struct BBC : BB, C
{
    using BB::BB;
    using C::C;
};

int main()
{
    BC(1, 1);  // this compiles
    BBC(1, 1); // this doesn't because it needs to defaultly
               // initialize the virtual base A who doesn't
               // have a default constructor
}

我了解为什么BBC不能根据上述答案提供的确切原因进行编译,我将在这里重复
[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]).



[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.



因此,基本上,虚拟基类需要默认构造,因为它不在BBC的继承构造函数的mem-initializer-list中。但是A没有默认的构造函数,因此会失败(添加A()=default;显然可以使其进行编译,但这不是重点)。

但是我还不清楚为什么BC没有这个问题?在继承构造函数部分中,它实际上是the same example given by cppreference。因此它必须工作。但这看起来与标准并不矛盾吗?当BA继承构造函数时,除了非默认值之外,它也什么也没有得到,它与BB中定义的初始化方法执行相同的初始化操作,只是隐式的。然后,当B进一步继承了BC的此构造方法时,难道不应该使用相同的规则来对A进行默认构造,从而不能对其进行编译吗?

编辑:@ j6t指出我正在看一个过时的标准草案。 new one确实与我之前发现的cppreference页更加一致。

我仍然不清楚的一件事是,它确实说明了如果选择了虚拟基本构造函数会发生什么,但是首先由孙子类BC继承了它吗?从相同的draft看来,using引入的虚拟基础构造函数将仅在派生类(在这种情况下为B)中考虑。 using中的BC如何继承上面两个级别的构造函数?

我期望的是,当BC using-声明构造函数时,最初由B继承自A的内容应首先被视为B构造函数,然后再由BC继承。但是事实并非如此。

最佳答案

我只是在编辑中回答您的问题。

... but how is [the virtual base constructor] inherited by the grandchild class BC in the first place?



您引用的paragraph说:

Constructors that are introduced by a using-declaration are treated as though they were constructors of the derived class when looking up the constructors of the derived class (class.qual) [...].



也就是说,它说这些构造函数是通过限定名称查找找到的。这使use-declaration有效地进行了递归操作:要在基类中查找事物,它使用限定名称查找,然后将找到的事物用于限定名称查找。

struct B使用using A::A时,当在A::A中查找构造函数时,它将使构造函数struct B可用。当struct BC使用using B::B时会发生这种情况;这是对B中名称struct B的限定查找;因此,它找到了构造函数A::A,并以此方式使A::Astruct BC中可用。

关于c++ - 为什么使用声明的继承构造函数不使用默认构造函数初始化虚拟基类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61358705/

相关文章:

c++ - 从任意数量的类派生

java - 类不继承自扩展至 JComponent 的类

python - 用python多重继承类实现的好习惯?

c++ - 消除可变类层次结构中无参数函数调用的歧义

c++ - C++中一些基本的继承问题

c++ - 在调用基类构造函数时声明默认构造函数

c++ - 使用虚拟继承的类似乎允许基类构造函数覆盖另一个基类的成员

c++ - 从 T ** reshape 为 vec<vec<T>> 时返回对临时错误的引用

C++ 代码未按预期运行(类和容器)

安卓NDK |如何调试应用程序启动或暂停应用程序直到调试器连接