c++ - 为什么使用声明的继承构造函数不使用默认构造函数初始化虚拟基类?
问题描述
我昨天偶然发现了一个使用声明的继承构造函数的问题。在仔细阅读答案以及链接的标准草案 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,命名在 using 声明的嵌套名称说明符中表示的基类和下面指定的表达式列表,并且其函数体中的复合语句为空([class.base.init])。
在非委托构造函数中,初始化按以下顺序进行:首先,并且仅对于最派生类 ([intro.object]) 的构造函数,虚拟基类按照它们出现在深度优先左侧的顺序进行初始化从右到右遍历基类的有向无环图,其中“从左到右”是派生类基类说明符列表中基类的出现顺序。
所以基本上虚拟基类需要默认构造,因为它不在继承构造函数的mem-initializer-listBBC
中。但是A
没有默认构造函数,所以它失败(添加A()=default;
显然可以使它编译,但这不是重点)。
但我还不清楚为什么BC
没有这个问题?它与继承构造函数部分中的 cppreference 给出的示例基本相同。所以它必须工作。但它看起来与标准不矛盾吗?当从 继承构造函数时,它也只得到非默认构造函数,它执行与 中定义的构造函数相同的初始化,除了是隐式的。那么当这个构造函数进一步被继承时,不应该同样的规则适用于默认构造的地方,因此不编译吗?B
A
BB
B
BC
A
编辑:@j6t 指出我正在查看一个过时的标准草案。新的确实更符合我之前找到的 cppreference 页面。
对我来说仍然不清楚的一件事是,它确实解释了如果选择了虚拟基础构造函数会发生什么,但它BC
首先是如何被孙子类继承的?从同一草案中,似乎using
只在派生类中考虑引入的虚拟基构造函数(B
在这种情况下)。using
in如何BC
继承上面两层的构造函数?
我期望的是,在BC
使用-声明构造函数时,最初由B
from继承的A
应该首先被视为B
构造函数,然后由BC
. 但事实并非如此。
解决方案
我只是在编辑中回答你的问题。
...但是[虚拟基构造函数]首先是如何被孙子类 BC 继承的呢?
你引用的段落说:
在查找派生类 ( class.qual )的构造函数时,由 using 声明引入的构造函数被视为派生类的构造函数[...]。
即,它说这些构造函数是通过限定名称查找找到的。这使得 using-declaration 有效地成为递归操作:为了在基类中查找事物,它使用限定名称查找,然后使其找到的事物可用于限定名称查找。
使用时,struct B
它using A::A
使构造A::A
函数在 中查找构造函数时可用struct B
。struct BC
使用时会发生这种情况using B::B
;这是对 中名称的限定B
查找struct B
;因此,它找到了构造函数A::A
,并以这种方式A::A
在struct BC
.
推荐阅读
- sharepoint - 使用 OR 和 IN 时 SharePoint CAML 查询不起作用
- azure-devops - Azure devops 管道条件名称
- machine-learning - ValueError: X.shape[1] = 1 应该等于 14,训练时的特征数
- javascript - 如何从网格中获取值并发布它们。EXTJS
- solr - 增量导入后 Apache Solr 仍保留旧数据
- ios - 使用 RxSwift 和 MVVM 显示活动指示器
- jquery - 将 datepicker 输入 maxDate 设置为 now()
- angularjs - Angularjs app.run() 中的变量如何能够从 app.directive() 访问?
- android - Kotlin Android Extensions vs Android Data Binding Library,内存使用
- python - D3.js 如何将 href 链接放入 rect 并在其旁边输出文本?