昨天我偶然发现了一个使用声明的继承构造函数的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。因此它必须工作。但这看起来与标准并不矛盾吗?当B
从A
继承构造函数时,除了非默认值之外,它也什么也没有得到,它与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::A
在struct BC
中可用。
关于c++ - 为什么使用声明的继承构造函数不使用默认构造函数初始化虚拟基类?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61358705/