首页 文章

将shared_ptr <Base>向下转换为shared_ptr <Derived>?

提问于
浏览
74

更新:此示例中的shared_ptr与Boost中的一样,但它不支持shared_polymorphic_downcast(或者dynamic_pointer_cast或static_pointer_cast)!

我正在尝试初始化一个派生类的共享指针,而不会丢失引用计数:

struct Base { };
struct Derived : public Base { };
shared_ptr<Base> base(new Base());
shared_ptr<Derived> derived;

// error: invalid conversion from 'Base* const' to 'Derived*'
derived = base;

到现在为止还挺好 . 我没想到C会隐式地将Base *转换为Derived * . 但是,我确实需要代码表示的功能(即,在向下转换基指针时保持引用计数) . 我的第一个想法是在Base中提供一个强制转换运算符,以便可以进行对Derived的隐式转换(对于pedants:我会检查向下转换是否有效,不要担心):

struct Base {
  operator Derived* ();
}
// ...
Base::operator Derived* () {
  return down_cast<Derived*>(this);
}

好吧,它没有帮助 . 似乎编译器完全忽略了我的类型转换操作符 . 任何想法如何使shared_ptr分配工作?加分: Base* const 是什么类型的? const Base* 我明白了,但 Base* const ?在这种情况下 const 指的是什么?

3 回答

  • 45

    你可以使用 dynamic_pointer_cast . 它由 std::shared_ptr 支持 .

    std::shared_ptr<Base> base (new Derived());
    std::shared_ptr<Derived> derived =
                   std::dynamic_pointer_cast<Derived> (base);
    

    另外,我不建议在基类中使用强制转换运算符 . 像这样的隐式转换可能会成为错误和错误的根源 .

    -Update:如果类型不是多态的,可以使用 std::static_pointer_cast .

  • 5

    我假设你正在使用 boost::shared_ptr ......我想你想dynamic_pointer_castshared_polymorphic_downcast .

    但是,这些需要多态类型 .

    Base * const是什么类型的? const Base *我明白了,但Base * const?在这种情况下const指的是什么?

    • const Base * 是一个指向常量 Base 的可变指针 .

    • Base const * 是一个指向常量 Base 的可变指针 .

    • Base * const 是一个指向可变 Base 的常量指针 .

    • Base const * const 是一个指向常量 Base 的常量指针 .

    这是一个最小的例子:

    struct Base { virtual ~Base() { } };   // dynamic casts require polymorphic types
    struct Derived : public Base { };
    
    boost::shared_ptr<Base> base(new Base());
    boost::shared_ptr<Derived> derived;
    derived = boost::static_pointer_cast<Derived>(base);
    derived = boost::dynamic_pointer_cast<Derived>(base);
    derived = boost::shared_polymorphic_downcast<Derived>(base);
    

    我不确定你的例子是否有意创建基类型的实例并将其强制转换,但它可以很好地说明差异 .

    static_pointer_cast 将"just do it" . 这将导致未定义的行为( Derived* 指向由 Base 分配和初始化的内存)并且可能导致崩溃,或者更糟 . base 上的引用计数将递增 .

    dynamic_pointer_cast 将导致空指针 . base 上的引用计数将保持不变 .

    shared_polymorphic_downcast 将与静态强制转换具有相同的结果,但会触发断言,而不是看似成功并导致未定义的行为 . base 上的引用计数将递增 .

    (dead link)

    有时候确定是否使用static_cast或dynamic_cast有点困难,并且您希望自己可以拥有两个世界 . 众所周知,dynamic_cast具有运行时开销,但它更安全,而static_cast根本没有开销,但它可能会无声地失败 . 如果你可以在调试版本中使用shared_dynamic_cast,在发布版本中使用shared_static_cast,那会有多好 . 好吧,这样的事情已经可以使用了,叫做shared_polymorphic_downcast .

  • 71

    If somebody gets here with boost::shared_ptr...

    这是您可以向下转换为派生的Boost shared_ptr的方法 . 假设Derived继承自Base .

    boost::shared_ptr<Base> bS;
    bS.reset(new Derived());
    
    boost::shared_ptr<Derived> dS = boost::dynamic_pointer_cast<Derived,Base>(bS);
    std::cout << "DerivedSPtr  is: " << std::boolalpha << (dS.get() != 0) << std::endl;
    

    确保'Base' class / struct至少有一个虚函数 . 虚拟析构函数也可以工作 .

相关问题