Динамические списки и полиморфизм

#c

#c

Вопрос:

У меня есть карта типа <lookup_ID, vector< parentclass *>> каждое местоположение на карте содержит вектор типа дочерний класс. Идея, лежащая в основе этой системы, заключается в возможности добавления дочернего элемента в связанную с ним карту с помощью функции add (parentclass *), и она сможет найти связанный с ней вектор дочернего типа. Я пытался использовать шаблоны и приведение, чтобы заставить вектор распознавать тип дочернего ввода в функцию добавления, но безуспешно. Я не хочу объявлять функцию add для каждого дочернего элемента parent, и независимо от того, как я это делал, мне приходилось объявлять функцию для каждого типа. Я мог бы удалить их из map, но опять же я остаюсь с проблемой вызова каждого дочернего элемента для любой функции, которую я хочу реализовать. Неужели у них нет способа сопоставить типы полиморфных структур с динамически распределяемыми списками?`

     class Piece
    {
    public:
    pieceType ID;
    //...
    }

    class Infantry :
        public Piece
    {
    public:
    //...
    };

    class Artillery :

        public Piece
    {
    public:
     //...
     };

//...

//In some other classes somewhere

std::map<pieceType, std::vector<Piece*>*> units;
        units.emplace(Infantry_, new std::vector<Infantry*>);
        units.emplace(Artillery_, new std::vector<Artillery*>);

//...
template<typename T>

std::vector<T*> operator (std::vector<T*> a, Piece * b) {

    a.push_back(static_cast<T*>(b));
    return a;

}

 add(Piece * piece){

units.at(piece->ID) = units.at(piece->ID)   piece;

}
  

Также я знаю, что в этом коде есть некоторые ошибки, это было больше для примера того, что я пытаюсь сказать.

Комментарии:

1. Приведенные ответы явно не указывают на это, но вы ищете некоторую форму того, что известно как самоанализ типа во время выполнения (RTTI). Проверьте документацию на TypeId.

Ответ №1:

Вы должны использовать виртуальную функцию, чтобы получить идентификатор для каждого дочернего класса

 class Piece
{
public:
  virtual PieceType ID() const = 0;
}

class Artillery
{
public:
  virtual PieceType ID() const override { /* return your ID for Artillery */ }
}

class Infantery
{
public:
  virtual PieceType ID() const override { /* return your ID for Infantery */ }
}
  

Ответ №2:

Между std::vector<Piece*> и любым из std::vector<Infantry*> или std::vector<Artillery*> нет никакой связи, поэтому ваша карта может содержать только std::vector<Piece*> s.

На это есть веская причина. Представьте, что у вас есть std::vector<Infantry*> , и поместите указатель на него в свой std::map<pieceType, std::vector<Piece*>*> . Затем вы могли бы вставить Artillery * в это через map.

Вместо того, чтобы предоставлять std::vector<Piece*> доступ напрямую, вы могли бы предоставить его представление (только для чтения), которое приводит к определенному подтипу.

Использование библиотеки ranges

 auto asInfantry = ranges::view::transform([](Piece * p){ return static_cast<Infantry *>(p); });
auto asArtillery = ranges::view::transform([](Piece * p){ return static_cast<Artillery *>(p); });

class PieceMap 
{
    std::map<pieceType, std::vector<Piece*>> units;

public:
    auto Infantry() { return units.at(Infantry_) | asInfantry; }
    auto Artillery() { return units.at(Artillery_) | asArtillery; }
};