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

Laj*_*agy 90 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;  
Run Code Online (Sandbox Code Playgroud)

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

struct Base {
  operator Derived* ();
}
// ...
Base::operator Derived* () {
  return down_cast<Derived*>(this);
}
Run Code Online (Sandbox Code Playgroud)

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

Mas*_*ari 89

你可以用dynamic_pointer_cast.它得到了支持std::shared_ptr.

std::shared_ptr<Base> base (new Derived());
std::shared_ptr<Derived> derived =
               std::dynamic_pointer_cast<Derived> (base);
Run Code Online (Sandbox Code Playgroud)

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

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

  • 我从第一行就不明白他没有使用`std :: shared_ptr`.但是从第一个答案的评论中我推断出他没有使用boost,所以他可能正在使用`std :: shared_ptr`. (3认同)

Tim*_*ter 46

我假设你正在使用boost::shared_ptr......我想你想要dynamic_pointer_cast或者shared_polymorphic_downcast.

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

什么样的类型Base* constconst Base*我理解,但是Base* constconst在这种情况下指的是什么?

  • 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);
Run Code Online (Sandbox Code Playgroud)

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

static_pointer_cast会"只管去做".这将导致未定义的行为(Derived*指向分配和初始化的内存Base)并且可能导致崩溃,或者更糟.引用计数base将增加.

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

shared_polymorphic_downcast将具有相同结果作为静态的演员,但会触发一个断言,而似乎获得成功,并导致不确定的行为.引用计数base将增加.

(死链接):

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

  • 如果没有实现其他`shared_ptr`构造函数(使用`static_cast_tag`和`dynamic_cast_tag`),那么你无能为力.你在`shared_ptr`之外做的任何事情都无法管理引用计数. - 在"完美"的OO设计中,您始终可以使用基类型,并且永远不需要知道也不关心派生类型是什么,因为它的所有功能都是通过基类接口公开的.也许你只需要重新思考为什么你需要首先进行下击. (3认同)

Mit*_*dra 5

如果有人来到这里与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;
Run Code Online (Sandbox Code Playgroud)

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