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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1358143/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-27 19:41:11  来源:igfitidea点击:

Downcasting shared_ptr<Base> to shared_ptr<Derived>?

c++gccboost

提问by Lajos Nagy

Update:the shared_ptr in this example is like the one in Boost, but it doesn't support shared_polymorphic_downcast (or dynamic_pointer_cast or static_pointer_cast for that matter)!

更新:本例中的 shared_ptr 与 Boost 中的类似,但它不支持 shared_polymorphic_downcast(或 dynamic_pointer_cast 或 static_pointer_cast)!

I'm trying to initialize a shared pointer to a derived class without losing the reference count:

我试图在不丢失引用计数的情况下初始化一个指向派生类的共享指针:

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;  

So far, so good. I didn't expect C++ to implicitly convert Base* to Derived*. However, I do want the functionality expressed by the code (that is, maintaining the reference count while downcasting the base pointer). My first thought was to provide a cast operator in Base so that an implicit conversion to Derived could take place (for pedants: I would check that the down cast is valid, don't worry):

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

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

Well, it didn't help. It seems the compiler completely ignored my typecast operator. Any ideas how I could make the shared_ptr assignment work? For extra points: what kind of type Base* constis? const Base*I understand, but Base* const? What does constrefer to in this case?

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

回答by Massood Khaari

You can use dynamic_pointer_cast. It is supported by std::shared_ptr.

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

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

Documentation: https://en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast

文档:https: //en.cppreference.com/w/cpp/memory/shared_ptr/pointer_cast

Also, I don't recommend using cast operator in the base class. Implicit casting like this may become the source of bugs and errors.

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

-Update:If the type is not polymorphic, std::static_pointer_castmay be used.

-更新:如果类型不是多态的,std::static_pointer_cast可以使用。

回答by Tim Sylvester

I assume you're using boost::shared_ptr... I think you want dynamic_pointer_castor shared_polymorphic_downcast.

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

However, these require polymorphic types.

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

what kind of type Base* constis? const Base*I understand, but Base* const? What does constrefer to in this case?

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

  • const Base *is a mutable pointer to a constant Base.
  • Base const *is a mutable pointer to a constant Base.
  • Base * constis a constant pointer to a mutable Base.
  • Base const * constis a constant pointer to a constant Base.
  • const Base *是一个指向常量的可变指针Base
  • Base const *是一个指向常量的可变指针Base
  • Base * const是一个指向 mutable 的常量指针Base
  • Base const * const是一个指向常量的常量指针Base

Here's a minimal example:

这是一个最小的例子:

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);

I'm not sure if it was intentional that your example creates an instance of the base type and casts it, but it serves to illustrate the difference nicely.

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

The static_pointer_castwill "just do it". This will result in undefined behavior (a Derived*pointing at memory allocated for and initialized by Base) and will likely cause a crash, or worse. The reference count on basewill be incremented.

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

The dynamic_pointer_castwill result in a null pointer. The reference count on basewill be unchanged.

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

The shared_polymorphic_downcastwill have the same result as a static cast, but will trigger an assertion, rather than seeming to succeed and leading to undefined behavior. The reference count on basewill be incremented.

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

See (dead link):

(死链接)

Sometimes it is a little hard to decide whether to use static_castor dynamic_cast, and you wish you could have a little bit of both worlds. It is well known that dynamic_cast has a runtime overhead, but it is safer, whereas static_cast has no overhead at all, but it may fail silently. How nice it would be if you could use shared_dynamic_castin debug builds, and shared_static_castin release builds. Well, such a thing is already available and is called shared_polymorphic_downcast.

有时决定是否使用static_cast或有点困难dynamic_cast,并且您希望可以兼具两者。众所周知,dynamic_cast 有运行时开销,但它更安全,而 static_cast 根本没有开销,但它可能会静默失败。如果您可以shared_dynamic_cast在调试版本和shared_static_cast发布版本中使用,那该有多好。嗯,这样的东西已经可用并且被称为shared_polymorphic_downcast

回答by Mitendra

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

如果有人带着 boost::shared_ptr 来到这里......

This is how you can downcast to the derived Boost shared_ptr. Assuming Derived inherits from Base.

这就是您如何向下转换到派生的 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;

Make sure 'Base' class/struct has at least one virtual function. A virtual destructor also works.

确保“Base”类/结构至少有一个虚函数。虚拟析构函数也有效。