【问题标题】:Downcasting shared_ptr<Base> to shared_ptr<Derived>?将 shared_ptr<Base> 向下转换为 shared_ptr<Derived>?
【发布时间】:2010-11-24 09:28:57
【问题描述】:

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

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

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(对于学究:我会检查向下强制转换是否有效,别担心):

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

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

【问题讨论】:

  • 为什么需要 shared_ptr 而不是 shared_ptr
  • 因为我想在不克隆对象的情况下访问 Derived 中不在 Base 中的功能(我想要一个由两个共享指针引用的对象)。顺便问一下,演员阵容为什么不工作?

标签: c++ gcc boost


【解决方案1】:

您可以使用dynamic_pointer_caststd::shared_ptr支持。

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

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

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

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

【讨论】:

  • 从第一行我不明白他没有使用std::shared_ptr。但是从第一个答案的cmets我推断他没有使用boost,所以他可能在使用std::shared_ptr
  • 好的。对不起。他应该更好地澄清他正在使用自定义实现。
【解决方案2】:

我假设你使用的是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 初始化的内存)并可能导致崩溃或更糟。 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

【讨论】:

  • 不幸的是,您的解决方案依赖于故意从我们正在使用的特定 shared_ptr 实现中排除的 Boost 功能(不要问为什么)。至于 const 的解释,现在更有意义了。
  • 没有实现其他shared_ptr 构造函数(采用static_cast_tagdynamic_cast_tag),您无能为力。您在shared_ptr 之外所做的任何事情都将无法管理引用计数。 -- 在“完美”的 OO 设计中,您始终可以使用基类型,而无需知道或关心派生类型是什么,因为它的所有功能都通过基类接口公开。也许您只需要重新考虑一下为什么首先需要向下转型。
  • @Tim Sylvester:但是,C++ 不是“完美”的面向对象语言! :-) 向下转型在不完美的面向对象语言中占有一席之地
【解决方案3】:

如果有人带着 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”类/结构至少有一个虚函数。虚拟析构函数也可以。

【讨论】:

    猜你喜欢
    • 2017-08-06
    • 2021-06-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-28
    • 2012-11-04
    • 1970-01-01
    相关资源
    最近更新 更多