Вывод типа производного объекта c ++ из списка базовых указателей - PullRequest
0 голосов
/ 24 марта 2020

У меня есть список указателей абстрактного класса. Класс определяется следующим образом, и мне нужно позже получить производный класс от содержащегося объекта:

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

1 Ответ

0 голосов
/ 25 марта 2020

Ваша data переменная std::map содержит элементы типа std::pair<const std::string, std::shared_ptr<IContainer>>, поэтому тип ixptr выводится как std::shared_ptr<IContainer>, поэтому ixptr-> возвращает указатель IContainer* и вызывает GetThis() по этому указателю возвращает IContainer& независимо от того, как классы-потомки переопределяют GetThis(). Таким образом, тип xptr выводится как IContainer&, и поскольку 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();
    ...
}

Этот лог c также может быть применен к вашему for l oop:

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 будет не nullptr для "val1", но будет nullptr для "val2", поскольку Container<int> и Container<double> являются отдельными и не связанными типами.

...