CRTP和向下转换

得到

先前的帖子中跟进了有关下垂和类型安全的类似问题,我想知道以下示例是否会创建未定义的行为。

已创建基类的实例。没有动态绑定发生。
但是,在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“指针CV2 D ”,其中D是衍生自完整的类B,如果CV2是相同的CV-资格,或更大cv资格比cv1更高[...]如果类型“指向cv1的 指针”的prvalue指向BaB实际上是该类型的对象的子对象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] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章