从基到派生的shared_ptr的C++dynamic_ptr_cast失败

C++ dynamic_ptr_cast of a shared_ptr from a base to derived fails

本文关键字:ptr cast 失败 C++dynamic shared 派生      更新时间:2023-10-16

这是我本周遇到的一个难题。这在一定程度上是因为在对Java进行了一段时间的编码之后,我刚刚返回到C++编码。给定以下代码:

class Base {
};
class A : Base {
public:
    virtual void run() { cout << "This is A." << endl; }
};
class B : Base {
public:
   virtual void run() { cout << "This is B." << endl; }
};
class C : A, B {
public:
   void run() { cout << "This is C." << endl; }
};
int main(int argc, char* argv[])
{
   shared_ptr<A> ptrToA = shared_ptr<C>(new C());
   cout << "Pointer to A: " << ptrToA.get() << endl;
   cout << "Dynamic Cast A ptr to C: " << dynamic_pointer_cast<C>(ptrToA) << endl;
   ptrToA->run();
   assert(dynamic_pointer_cast<C>(ptrToA));
   cout << "Success!" << endl;
}

为什么它会产生以下输出?

Pointer to A: 0x1f29c010
Dynamic Cast A ptr to C: 0
Running...
This is C.
tester-cpp: tester.cpp:89: int main(int, char **): Assertion `dynamic_pointer_cast<C>(ptrToA)' failed.

因为"This is C"打印出来,所以多态性显然是有效的,但当将shared_ptr从"a"基类动态转换为"C"时,它会失败。这周我在这个微妙的问题上浪费了好几个小时的时间!希望任何答案都能避免未来遇到类似问题的程序员浪费太多时间(这个错误非常微妙,尤其是在编写Java代码一段时间后)。

为什么?(我给你一个提示…此代码是用Linux上的英特尔C++编译器12.1.0编译的。我用另一个编译器尝试过,但我的代码编译失败!

它在另一个编译器上编译失败的事实是一个提示:它真的应该编译失败。这是因为C私有继承自AB,因此C*不应转换为A*。因此,shared_ptr<A> ptrToA = shared_ptr<C>(new C());应该无法编译,因为只有当指针可以根据标准转换时,会话构造函数才应该参与重载解析。因此,这看起来像是英特尔C++使用的标准库中的一个错误。

Class C: A, B更改为Class C: public A, public B,它应该可以工作。在gcc 4.6上测试,该代码确实无法使用私有继承进行编译,并且与A的公共继承一样工作。

由于您的代码包含菱形继承,您可能还想了解一下虚拟继承。