Обработка коллекции указателей на экземпляры производного класса, как если бы они были родительским классом

0

(На этот вопрос, вероятно, уже был дан ответ, и я могу найти похожие вопросы, но ничего, что я могу применить к моей ситуации. Разумеется, ссылки на соответствующие вопросы приветствуются.)

Вот иллюстрация того, что я пытаюсь сделать:

    #include <vector>

    class Abstract
    {
    public:
        virtual std::vector<Abstract *> children() = 0;
    };

    class Concrete : public Abstract
    {
    public:
        std::vector<Abstract *> children() override {return std::vector<Abstract *>();} 
/* This returns an empty vector. What should actually go here, to return the actual children? */
    private:
        std::vector<Concrete *> m_children;
    };

    void doSomething(Abstract *a)
    {

    }

    int main()
    {
        Concrete c;

        for(auto& object : c.children())
            doSomething(object);
    }

Другими словами, мои объекты Concrete имеют собственные экземпляры собственного класса в качестве дочерних. Другой код хочет рассматривать их как их базовый базовый класс. Я могу придумать несколько способов добиться этого, но я изо всех сил стараюсь найти элегантный. Было бы неплохо, если бы мои классы поддерживали итерацию, но я не могу заставить ее работать с виртуальными абстрактными функциями. Я попробовал это:

(в реферате)

virtual std::vector<const Abstract *>::const_iterator begin() const = 0;
virtual std::vector<const Abstract *>::const_iterator end() const = 0;
virtual std::vector<Abstract *>::iterator begin() = 0;
virtual std::vector<Abstract *>::iterator end() = 0;

но что мне делать в Concrete :: begin() (где m_ children объявляется как

m_children std::vector<Concrete *>

)? Я начал так:

    std::vector<const Abstract *>::const_iterator it;
    Abstract *first = *m_children.begin();

... думая, что я могу иметь "это", указывая на первый экземпляр в моем векторе. Здесь, где я в тупик.

Предложения оценены!

  • 1
    Почему бы не хранить std::vector<Abstract*> вместо std :: vector <Concrete *> `?
  • 0
    Вы уверены, что children не должны возвращать const& ?
Показать ещё 8 комментариев
Теги:
c++11
iterator
stl
covariance

1 ответ

0

В С++ 11,

return { begin(vec), end(vec) };

преобразует вектор конкретных указателей в вектор абстрактного. Это так просто.

В С++ 03 вам придется явно вызвать конструктор и использовать .begin вместо бесплатной функции.

Итератор литья, который принимает итераторы к конкретному и создает итераторы-абстрактные, может быть написан либо с помощью boost, либо вручную, а затем с диапазоном retired.

Тип, стирающий итераторы, чтобы они были просто "универсальными итераторами для abstract* ", может выполняться либо с повышением, либо без. Это добавляет накладные расходы (которые могут быть существенными, если их не делать осторожно), и их следует учитывать только в том случае, если указанные выше два варианта оказались проблематичными, и это продемонстрировано, чтобы устранить проблему в реальных тестах.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню