将shared_ptr <base />向下转换为shared_ptr <derived>?</derived>

时间:2009-08-31 16:02:57

标签: c++ gcc boost

更新:此示例中的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 个答案:

答案 0 :(得分:77)

您可以使用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

答案 1 :(得分:46)

我假设您正在使用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将“正好”。这将导致未定义的行为(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

答案 2 :(得分:4)

如果有人使用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'类/结构至少有一个虚函数。虚拟析构函数也可以工作。