HTN*_*TNW 6 c++ language-lawyer
也就是说,这样的事情总是合法的吗?
struct Derived;
struct Base { Base(Derived*); };
struct Derived : Base { Derived() : Base(this) { } };
Base::Base(Derived *self) {
if(static_cast<Base*>(self) != this) std::terminate();
}
int main() {
Derived d; // is this well-defined to never call terminate?
}
Run Code Online (Sandbox Code Playgroud)
在static_cast求值时,self还没有指向一个Derived对象——那个对象正在构建中。例如,如果Derived有数据成员,它们的构造函数就不会被调用。是否仍然保证强制转换是定义的行为,从而产生一个与Base's等效的指针this(它确实指向一个完全构造的Base基类子对象)?
我认为接近回答这个问题的标准引语是[conv.ptr]/3。
...转换的结果是一个指向派生类对象的基类子对象的指针。...
但我认为是没有派生类对象还没有,那么会发生什么?如果它确实是未定义的,答案会改变self != static_cast<Derived*>(this)吗?
(Clang 和 GCC 编译并“按预期”运行。)
这很好:[class.cdtor]/3说
显式或隐式地将引用类对象的指针(泛左值)转换为指向 的直接或间接基类的
X指针(引用),以及直接或间接构建其所有直接或间接基类的指针(引用)派生自应已开始,并且这些类的销毁尚未完成,否则转换会导致未定义的行为。...BXXB
它要求源类型(以及从目标类型继承的任何其他基类)已经开始其构造函数并且尚未完成其析构函数。甚至基类的初始值设定项也算作派生构造函数的开始;该标准包含一个非常相似的示例。