【问题标题】:C++ dynamic_ptr_cast of a shared_ptr from a base to derived fails从基础到派生的 shared_ptr 的 C++ dynamic_ptr_cast 失败
【发布时间】:2012-01-26 19:02:32
【问题描述】:

这是我本周遇到的一个难题。部分原因是我在编写 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 上使用 Intel C++ 编译器 12.1.0 编译的。我用另一个编译器尝试过,我的代码编译失败!

【问题讨论】:

  • 因为C 私下继承自AB;将class C : A, B 更改为class C : public A, public Bstruct C : A, B。此外,使用A* 时会打印出“This is C”,但我怀疑使用B* 时不会打印出来; run() 最初可能需要在 Base 中声明,并且您可能需要使用虚拟继承。
  • 您使用的是shared_ptr 的什么实现?我预计shared_ptr&lt;A&gt; ptrToA = shared_ptr&lt;C&gt;(new C()); 会失败,因为AC 的一个不可访问的基础。
  • 你应该在没有智能指针的情况下尝试它,然后我怀疑这可能适用:stackoverflow.com/questions/7210321/…
  • gcc 无法编译,并出现“错误:从 'std::shared_ptr' 转换为非标量类型 'std::shared_ptr' 请求”,我认为应该如此。
  • 具有讽刺意味的是,我们的 makefile 被设置为引入 std::tr1::shared_ptr 的 g++ 实现!用gcc编译时,我的4.5报错“‘A’ is an inaccessible base of ‘C’”,问题就很明显了。

标签: c++ polymorphism shared-ptr


【解决方案1】:

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

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

由于您的代码包含diamond inheritance,您可能还想查看virtual inheritance

【讨论】:

  • 说得好,是的,我的原始代码在“Base”上没有虚拟继承(当时我在想更多的 java 接口......),但可能应该。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-07-23
  • 2011-09-05
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多