【问题标题】:Deducing the type of c++ derived object from list of base pointers从基指针列表中推断出 c++ 派生对象的类型
【发布时间】:2020-03-24 18:23:52
【问题描述】:

我有一个抽象类的指针列表。类定义如下,后面需要从包含的对象中获取派生类:

class IContainer {
  class TT;

public:
  ~IContainer() = default;

  auto& GetType() const {
    return *this;
  }

  virtual IContainer& GetThis() = 0;

};

template <typename Type>
class Container : public IContainer {
  using TT = Type;

public:
  Container(const Type& var) : var_{var} {}
  Type GetVar2() { return var_; }
  Type var_{};

  // This method is returning IContainer, yet am expecting derived one
  Container<Type>& GetThis() override {
    std::cout << "name: " << typeid(TT).name() << std::endl;
    return static_cast<Container<Type>&>(*this);
  }
};

我喜欢用它

  std::map<std::string, std::shared_ptr<IContainer>> data;
  int x{5};
  using Type = Container<decltype(x)>;
  data["val1"] = std::make_shared<Type>(x);
  double y{2.3};
  data["val2"] = std::make_shared<Container<decltype(y)>>(y);

  auto& ixptr = data.at("val1");
  auto& xptr = ixptr->GetThis();

  xptr.GetVar2(); //NOT WORKING

其实我想访问_var。 如何用 c++ 14 做到这一点? 信息:我收到此错误消息:

error: ‘class IContainer’ has no member named ‘GetVar2

【问题讨论】:

  • 这行不通。如果密钥由用户提供而不是硬编码(即ixptr = data.at(user_supplied_value)),这段代码应该做什么?
  • 不会提供他们的密钥。这仅用于演示。最后我会有for (const aut auto&amp; datum : data)。你也可以把它想象成简单的 std::vector
  • 这就是我的观点。你有一个 static 类型。它不能是变量:您想要的意味着在您的for 循环的后续迭代中,循环变量的静态类型会有所不同。这在 C++ 中不受支持。
  • 其实我想要一种c++ 17 std::variant。
  • 为什么不在派生类中加入一个函数来报告派生类的类型呢?就像让它返回一个表示类型的值,并且在函数中只为派生类类型 0 返回 0,为派生类类型 1 等返回 1。

标签: c++ templates c++14 type-deduction return-type-deduction


【解决方案1】:

你的data变量是一个std::map持有std::pair&lt;const std::string, std::shared_ptr&lt;IContainer&gt;&gt;类型的元素,所以ixptr的类型被推断为std::shared_ptr&lt;IContainer&gt;,因此ixptr-&gt;返回一个IContainer*指针,并调用@987654328无论后代类如何覆盖GetThis(),该指针上的@ 都会返回IContainer&amp;。所以xptr的类型推导出为IContainer&amp;,由于IContainer没有GetVar2()方法,所以xptr.GetVar2()编译失败。

dynamic_cast可以用来解决这个问题,例如:

auto &ixptr = data.at(...);
auto &xptr = ixptr->GetThis();

auto *xptr_int = dynamic_cast<Container<int>*>(&xptr);
if (xptr_int)
{
    int var2 = xptr_int->GetVar2();
    ...
}

这个逻辑也可以应用于你的for循环:

for (const auto &datum : data)
{
    auto &xptr = datum.second->GetThis();
    auto *xptr_int = dynamic_cast<Container<int>*>(&xptr);
    if (xptr_int)
    {
        int var2 = xptr_int->GetVar2();
        ...
    }
}

xptr_int 对于"val1" 将不是nullptr,但对于"val2" 将是nullptr,因为Container&lt;int&gt;Container&lt;double&gt; 是独立且不相关的类型。

【讨论】:

  • 谢谢,但是如何在if(xptr) 之外使用var2。似乎我需要重复代码
  • 只需将var2 的声明移到if 的上方,并在dynamic_cast 返回nullptr 时给它一个合理的默认值,例如:int var2 = 0; if (xptr_int) { var2 = xptr_int-&gt;GetVar2(); } // use var2 as needed ...
猜你喜欢
  • 2011-07-20
  • 2014-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-07-02
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多