C++ 关于C&x2B中的第12.7p3段+;标准,我有以下问题
在本条款C++ 关于C&x2B中的第12.7p3段+;标准,我有以下问题,c++,c++11,constructor,standards,implicit-conversion,C++,C++11,Constructor,Standards,Implicit Conversion,在本条款12.7p3规定的限制条件下,可以避免哪些具体问题(见下文第一部分) 在12.7p3(见下文)所示的示例中,为什么认为定义了X(此)?是因为X不在路径ecdba中吗 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:
12.7p3
规定的限制条件下,可以避免哪些具体问题(见下文第一部分)
12.7p3
(见下文)所示的示例中,为什么认为定义了X(此)
?是因为X
不在路径ecdba
中吗
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
}
};
12.7p3
的开头:X
的所有直接和间接基不包括B
,因此下面的代码定义得很好,尽管Base
是派生的
的直接基,并且尚未开始,这样说是否正确
struct Base{ Base(Base*); };
struct Derived : Base {
Derived() : Base(this) {};
};
第12.7p3条规定的限制可避免哪些具体问题(见下文第一部分)
问题在于,在某些时候,必须为派生类初始化虚拟指针(指向虚拟表或虚拟基类)。这是在“初始化列表”期间(即,在构造函数主体开始之前)发生的初始化,通常在构建基类之后发生(例如,在构造基类B之后,为类X设置虚拟表指针和可能的虚拟基指针,然后初始化数据成员,然后开始构造函数的主体)。通常,在初始化这些指针之前执行上转换将产生未定义的行为,原因可能是无法对虚拟基执行所需的指针查找,或者虚拟表指针设置不正确,无法正确调用虚拟函数
在12.7p3(见下文)所示的示例中,为什么认为X(这)是定义的?是因为X不在路径E C D B A中吗
因为基类构造函数是按照它们在类声明中出现的顺序调用的(即,struct e:C,D,X{
).因为基类C和D都是构造的,所以它们的公共虚拟基类A肯定也是构造的。而且因为X
不是从类A
继承的,这意味着在此时执行从类E
到类A
的转换时,有一条完全构造且明确的路径。Th这就是为什么这条线定义明确
上面提到的X的所有直接基和间接基不包括B,因此下面的代码定义得很好,尽管Base是派生的直接基并且还没有开始,这是正确的吗
我不确定我是否理解您的解释,但我可以告诉您,您显示的代码没有很好的定义。当通过将Derived*this
强制转换为Base*
来调用Base
的构造函数时,派生类中的基类对象尚未构造,因此强制转换未定义
此代码有意义的唯一方法是,如果层次结构中没有涉及虚拟函数或虚拟基类,则不需要此类代码,因为指向基类的
this
指针已隐式发送给基类构造函数。+1,不确定是否值得注意,但在示例f中如果行D(this)
被重写为D(static_cast(this)),则从标准中读取
它将被完美地定义。问题只会出现在编译器可能决定使用D
的基来解析A
子对象的位置时。我不确定我是否同意您在最后的派生:基
示例中得出的结论。基
不是“直接或间接派生自基的派生的
的直接或间接基”(满足第一个条件,它是派生的
的基,但它不是从自身派生的)@Mikael认为构造函数中的任何虚拟调用总是指向与正在构造的对象相对应的成员函数,这不是很正确吗?如果是这种情况,我不明白为什么这个子句对于避免您在解释中提到的那种问题如此重要。@BenVoigt不是一个总是被轻视的类直接从自身派生?(即,对象始终是自身的子对象)我同意,在这种情况下,代码在现实生活中可能会像预期的那样工作,只是因为没有涉及虚拟继承。如果Base是派生的虚拟Base,那么代码将是未定义的行为,因为cast在技术上依赖于基类指针,而现在不是。因为12.7p3没有提出这一点区别在于,我别无选择,只能做出最保守的假设。@user2337207在基类构造函数(虚拟函数与之绑定)之前调用初始化列表中的虚拟成员函数has completed是未定义的行为,请参见12.6.2/13。要点是,虚拟表和虚拟基指针在基类构造函数完成后立即初始化,因此,它们的任何使用(调用虚拟函数或强制转换到虚拟基)是未定义的行为,直到该点为止,无论编译器在理论上是否可以在没有这些指针的情况下正确地进行调用或强制转换。12.7/3采取保守的立场。+1只是为了在