基类有时可以初始化派生类的成员吗?
该程序是否具有明确定义的行为?
struct Foo;
struct FooImpl {
FooImpl();
};
struct Foo : FooImpl {
int bar;
};
FooImpl::FooImpl() {
static_cast<Foo *>(this)->bar = 0;
}
int main() {
return Foo().bar;
}
需要特别注意的是,它Foo::bar是默认初始化的。我知道如果Foo::bar被初始化Foo,这肯定是不好的,因此这个特殊的例子。
请记住,这是一个用于说明案例的简化示例。我对 C++ 规范对此的看法感兴趣(而不是这在风格上是好还是坏的代码)。
回答
一般来说,父母可以访问孩子的成员。就像CRTP一样。
但是,在析构函数和构造函数中访问它们会直接导致 UB。
FooImpl::FooImpl()
{
static_cast<Foo *>(this)->bar = 0;
}
这是 UB,因为Foo和 随后bar尚未构建,并且您已经访问它(并修改它!)。同样在析构函数中 - 此时bar已经被删除。相反,您可以使用相同的主体创建Initialize()方法FooImpl并在Foo的构造函数中调用它,那么它就是合法的。