为什么使用声明的继承构造函数不使用默认构造函数初始化虚拟基class?
Why does using-declared inheriting constructor NOT initialize the virtual base class using a default constructor?
我偶然发现了一个 question of the using-declared inheriting constructor yesterday. And after carefully reading the answer as well as the linked standard draft N3337,我发现当直接基础 class 也使用 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]).
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.
所以基本上虚基 class 需要默认构造,因为它不在 [=13= 的继承构造函数的 mem-initializer-list 中].但是 A
没有默认构造函数,所以它失败了(添加 A()=default;
显然可以使其编译,但这不是这里的重点)。
但是我还不清楚为什么BC
没有这个问题?它本质上是 Inheriting constructors 部分中的 the same example given by cppreference。所以它必须工作。但这看起来不与标准相矛盾吗?当 B
从 A
继承构造函数时,它也只获得非默认构造函数,它执行与 BB
中定义的构造函数相同的初始化,除了是隐式的。然后,当 B
的这个构造函数被 BC
进一步继承时,是否应该应用相同的规则,其中 A
将被默认构造,因此无法编译?
编辑:@j6t 指出我在看一份过时的标准草案。 new one 确实更符合我之前找到的 cppreference 页面。
我仍然不清楚的一件事是,它确实解释了如果选择了虚拟基础构造函数会发生什么,但是它首先是如何被孙子 class BC
继承的?从同一个 draft 来看,using
引入的虚基构造函数似乎只会在派生的 class 中考虑(在本例中为 B
)。 BC
中的 using
是如何继承上两层的构造函数的?
我期望的是,当BC
使用-声明构造函数时,最初由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) [...].
也就是说,这些构造函数是通过限定名称查找找到的。这使得 using 声明有效地成为递归操作:要在基 class 中查找事物,它使用限定名称查找,然后使它找到的事物可用于限定名称查找。
当 struct B
使用 using A::A
时,它使构造函数 A::A
在 struct B
中查找构造函数时可用。当 struct BC
使用 using B::B
时会发生这种情况;这是 struct B
中名称 B
的限定查找;因此,它找到构造函数 A::A
,并以这种方式使 A::A
在 struct BC
.
中可用
我偶然发现了一个 question of the using-declared inheriting constructor yesterday. And after carefully reading the answer as well as the linked standard draft N3337,我发现当直接基础 class 也使用 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]).
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.
所以基本上虚基 class 需要默认构造,因为它不在 [=13= 的继承构造函数的 mem-initializer-list 中].但是 A
没有默认构造函数,所以它失败了(添加 A()=default;
显然可以使其编译,但这不是这里的重点)。
但是我还不清楚为什么BC
没有这个问题?它本质上是 Inheriting constructors 部分中的 the same example given by cppreference。所以它必须工作。但这看起来不与标准相矛盾吗?当 B
从 A
继承构造函数时,它也只获得非默认构造函数,它执行与 BB
中定义的构造函数相同的初始化,除了是隐式的。然后,当 B
的这个构造函数被 BC
进一步继承时,是否应该应用相同的规则,其中 A
将被默认构造,因此无法编译?
编辑:@j6t 指出我在看一份过时的标准草案。 new one 确实更符合我之前找到的 cppreference 页面。
我仍然不清楚的一件事是,它确实解释了如果选择了虚拟基础构造函数会发生什么,但是它首先是如何被孙子 class BC
继承的?从同一个 draft 来看,using
引入的虚基构造函数似乎只会在派生的 class 中考虑(在本例中为 B
)。 BC
中的 using
是如何继承上两层的构造函数的?
我期望的是,当BC
使用-声明构造函数时,最初由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) [...].
也就是说,这些构造函数是通过限定名称查找找到的。这使得 using 声明有效地成为递归操作:要在基 class 中查找事物,它使用限定名称查找,然后使它找到的事物可用于限定名称查找。
当 struct B
使用 using A::A
时,它使构造函数 A::A
在 struct B
中查找构造函数时可用。当 struct BC
使用 using B::B
时会发生这种情况;这是 struct B
中名称 B
的限定查找;因此,它找到构造函数 A::A
,并以这种方式使 A::A
在 struct BC
.