我在一个偶然的问题昨天通过声明的继承构造函数。在仔细阅读了答案以及链接的标准草案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
隐式定义的继承构造函数将通过用户编写的内联构造函数对该类进行初始化,该类由用户编写的内联构造函数使用mem-initializer-list进行执行,该列表的唯一mem-initializer具有一个mem-initializer-id来命名使用声明的嵌套名称说明符中指定的基类,以及下面指定的表达式列表,并且其功能主体中的复合语句为空([class.base.init])。
在非委托的构造函数中,初始化按以下顺序进行:首先,并且仅对于最派生类([intro.object])的构造函数,虚拟基类将按照它们出现在深度优先左侧的顺序进行初始化。基类的有向无环图的从右到右遍历,其中“从左到右”是基类在派生类base-specifier-list中的出现顺序。
因此,基本上,虚拟基类需要默认构造,因为它不在继承的构造函数的mem-initializer-list中BBC
。但是A
没有默认的构造函数,因此会失败(添加A()=default;
显然可以使其编译,但这不是重点)。
但是我还不清楚为什么BC
没有这个问题?从本质上讲,它与cppreference在“继承的构造函数”部分给出的示例相同。因此它必须工作。但这看起来与标准并不矛盾吗?当B
从中继承构造函数时A
,除了非默认值外,它什么也不会得到,它与定义的默认值执行相同的初始化BB
,只是隐式的。然后,当fromB
进一步继承此构造方法时BC
,难道不是同一规则适用于A
默认构造的地方,因此无法编译吗?
编辑:@ j6t指出我正在看一个过时的标准草案。在新的的确符合与cppreference页我发现较早更好。
我仍然不清楚的一件事是,它确实说明了如果选择了虚拟基础构造函数会发生什么情况,但是首先由孙子类继承的是什么BC
?从同一草稿开始,似乎using
仅在派生类中考虑引入的虚拟基构造函数(B
在这种情况下)。如何using
在BC
继承一个构造函数,是上述两种电平?
我期望的是,在BC
使用-declare构造函数时,最初由B
from继承的最初A
应该被视为B
构造函数,然后再由继承BC
。但是事实并非如此。
我只是在编辑中回答您的问题。
...但是首先,孙子类BC如何继承[虚拟基本构造函数]?
您引用的段落说:
在查询派生类的构造函数(class.qual)[...]时,将使用using声明引入的构造函数视为派生类的构造函数。
即,它说这些构造函数是通过限定名称查找找到的。这使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
。
本文收集自互联网,转载请注明来源。
如有侵权,请联系[email protected] 删除。
我来说两句