在先前的帖子中跟进了有关下垂和类型安全的类似问题,我想知道以下示例是否会创建未定义的行为。
已创建基类的实例。没有动态绑定发生。
但是,在Base :: interface函数中,Base类的实例被强制转换为Derived类的实例。这样安全吗?如果可以,为什么?请在下面找到这段代码。
#include <iostream>
template <typename Derived>
struct Base{
void interface(){
static_cast<Derived*>(this)->implementation();
}
};
struct Derived1: Base<Derived1>{
void implementation(){
std::cout << "Implementation Derived1" << std::endl;
}
};
int main(){
std::cout << std::endl;
Base<Derived1> d1;
d1.interface();
std::cout << std::endl;
}
没有Derived
,这个新的Derived *
可能指向,所以这绝不是安全的:演员本身具有不确定的行为,如[expr.static.cast]§11(重点煤矿)描述:
类型的prvalue“指针CV1
B
”,其中B
是一个类型,可以转化成类型的prvalue“指针CV2D
”,其中D
是衍生自完整的类B
,如果CV2是相同的CV-资格,或更大cv资格比cv1更高。[...]如果类型“指向cv1的 指针”的prvalue指向B
aB
实际上是该类型的对象的子对象D
,则结果指针将指向类型的封闭对象D
。否则,行为是undefined。
您可以通过限制访问Base
的构造函数来减轻这种风险:
template <typename Derived>
struct Base{
// Same as before...
protected:
Base() = default;
};
这样比较好,但是如果有人不小心定义,仍然会出现相同的问题struct Derived2 : Base<AnotherDerived> { };
。可以通过特定的friend
声明来防止这种情况的发生,但是它不利于完全访问Base
的私有成员:
template <typename Derived>
struct Base{
// Same as before...
private:
friend Derived;
Base() = default;
};
请注意,这仍然允许在其成员函数中Derived
构造裸Base<Derived>
对象,但这是我通常停止重整痣的地方。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句