Ale*_*der 10 c++ standards constructor implicit-conversion c++11
本条款施加的限制可以避免哪些具体问题12.7p3(见下段第一部分)?
在12.7p3(见下文)所示的例子中,为什么X(this)被认为是定义的?是因为X不在路上E C D B A吗?
struct A { };
struct B : virtual A { };
struct C : B { };
struct D : virtual A { D(A*); };
struct X { X(A*); };
struct E : C, D, X {
E() : D(this), // undefined: upcast from E* to A*
// might use path E* - D* - A*
// but D is not constructed
// D((C*)this), // defined:
// E* - C* defined because E() has started
// and C* - A* defined because
// C fully constructed
X(this) { // defined: upon construction of X,
// C/B/D/A sublattice is fully constructed
}
};
Run Code Online (Sandbox Code Playgroud)请在下面的段落开头找到12.7p3:
显式或隐式地将引用类X的对象的指针(glvalue)转换为指向X的直接或间接基类B的指针(引用),构造X及其所有直接或间接基础的构造直接或间接从B派生的应该已经开始并且这些类的销毁不应该完成,否则转换会导致不确定的行为.
如果说X上面提到的所有直接和间接基础的集合都不包括在内B,并且正因为如此,下面的代码是明确定义的,尽管这Base是直接的基础Derived并且尚未开始,这是正确的吗?
struct Base{ Base(Base*); };
struct Derived : Base {
Derived() : Base(this) {};
};
Run Code Online (Sandbox Code Playgroud)
12.7p3规定的限制可以避免哪些具体问题(见下段第一部分)?
这些问题与以下事实有关:在某些时候,必须为派生类初始化虚拟指针(虚拟表或虚拟基类).这是在"初始化列表"期间(即,在构造函数体开始之前)发生的初始化,通常在构造基类之后(例如,在构造基类B之后,虚拟表指针和可能的虚拟基指针)为类X设置,然后初始化数据成员,然后构造函数的主体开始).通常,在初始化这些指针之前执行向上转换将产生未定义的行为,因为无法对虚拟基础执行所需的指针查找,或者无法正确设置虚拟表指针以正确调用虚函数.
在12.7p3(见下文)中显示的示例中,为什么X(this)被认为是定义的?是因为X不在路径ECDBA中吗?
因为基类构造函数按它们出现在类声明中的顺序调用(即,struct E : C, D, X {).因为基类C和D都是构造的,所以它们的公共虚拟基类A当然也是构造的.并且因为X不从类继承A,这意味着在此时执行从类E到类的转换时存在完全构造且明确的路径A.这就是为什么这条线是明确定义的.
如果说上面提到的X的所有直接和间接基数的集合都不包括B是正确的,并且由于这个原因,下面的代码是明确定义的,尽管Base是Derived的直接基础并且还没有没有开始?
我不确定我是否按照你的解释,但我可以告诉你,你展示的代码没有明确定义.当Base通过强制转换Derived* this来调用构造函数时,Base*派生类中的基类对象尚未构造,因此,未定义强制转换.
这个代码有意义的唯一方法是,如果层次结构中没有涉及虚函数或虚拟基类,在这种情况下,由于this指向基类的指针已经隐式地发送到基类,因此不需要这样的代码.基类构造函数.