【问题标题】:std::dynamic_pointer_cast isn't casting correctly downwardsstd::dynamic_pointer_cast 没有正确向下投射
【发布时间】:2014-08-23 04:55:20
【问题描述】:

我有一个问题,我会在发布代码后解释:

template <class T> 
std::shared_ptr<T>
getWidget(const std::string& id) {
  auto iter = findObject(id);

  if (iter != m_widgets.end()) return std::dynamic_pointer_cast<T>(*iter);

  return nullptr;
}

const Widget::Ptr
getType(const std::string& id) {
  auto iter = findObject(id);

  if (iter != m_widgets.end()) {
    if ((*iter)->getWidgetType() == "Label")
      return std::dynamic_pointer_cast<Label>(*iter);
    else if ((*iter)->getWidgetType() == "Editbox")
      return std::dynamic_pointer_cast<EditBox>(*iter);
    else if ((*iter)->getWidgetType() == "ButtonLabel")
      return std::dynamic_pointer_cast<ButtonLabel>(*iter);
    else if ((*iter)->getWidgetType() == "Menu")
      return std::dynamic_pointer_cast<Menu>(*iter);
  }
}

auto type = SceneManager::getCurrentScene().m_gui.getType(widgetId);

SceneManager::getCurrentScene().m_gui.getWidget<decltype(type)>(widgetId)->attachToMenu(getId());

Widget::Ptr 只是一个typedef std::shared_ptr&lt;Widget&gt;。如您所见,m_widgets 是一个包含 Widget 的列表,这些 Widget 是 LabelEditBoxButtonLabel 和 Menu 的基类。我正在尝试向下转换到这些类,以便我可以获取类型,并使用我的getWidget() 来编辑派生对象。但是我收到了这个错误:

错误:“class std::shared_ptr”没有名为“attachToMenu”的成员|

这显然意味着它没有正确投射并且它正在返回一个小部件。任何帮助都会很棒,谢谢!

【问题讨论】:

  • iter == m_widgets.end() 的情况下,您有未定义的行为。在这种情况下可能要添加return nullptr
  • 你认为decltype(type)是什么?
  • 如果我没看错,decltype(type) 是一个std::shared_ptr&lt;Widget&gt;,所以getWidget 返回一个std::shared_ptr&lt;std::shared_ptr&lt;Widget&gt;&gt;,然后调用-&gt;attachToMenu(…) 是不行的。
  • 低调工作正常。 getType 的返回类型导致向上转换回 Widget::Ptr

标签: c++ templates stl casting smart-pointers


【解决方案1】:

“Widget::Ptr 只是一个 typedef std::shared_ptr。”

我假设它是 std::shared_ptr&lt;Widget&gt; 的 typedef。如果是这样,那么dynamic_pointer_cast 只在函数体内向下转换,在它之外的类型是std::shared_ptr&lt;Widget&gt;(这是因为返回类型意味着向上转换):

auto type = SceneManager::getCurrentScene().m_gui.getType(widgetId);
// type is std::shared_ptr<Widget>, that is, a pointer to base type

此外,使用getWidget&lt;decltype(type)&gt; 您实际上希望getWidget&lt;T&gt; 返回std::shared_ptr&lt;std::shared_ptr&lt;Widget&gt;&gt;,这与您想要实现的目标相去甚远。

最终,向下转换通常表示糟糕的设计。我相信你的问题可以通过在Widget 基类中使attachToMenu 方法虚拟来解决,那么你在运行时不需要RTTI。考虑一下:

class Widget
{
public:
    virtual ~Widget() = default;
    virtual void attachToMenu(const std::string& id) = 0;
};

class EditBox : public Widget
{
public:
    virtual void attachToMenu(const std::string& id) override
    {
        // do the stuff
    }
};

std::shared_ptr<Widget> widget = std::make_shared<EditBox>();
widget->attachToMenu(getId()); // calls EditBox::attachToMenu

【讨论】:

    【解决方案2】:

    当你声明时

    auto type = ...
    

    type 的类型将始终为Widget::Ptr,因为这是函数返回的类型。所有向下转换都发生在函数内,所以没关系。然后,当您使用decltype(type) 调用getWidget 时,将使用静态类型,所以再次使用Widget::Ptr。你需要重新设计。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-08-18
      • 1970-01-01
      • 1970-01-01
      • 2015-12-23
      • 1970-01-01
      • 2018-05-09
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多