(На этот вопрос, вероятно, уже был дан ответ, и я могу найти похожие вопросы, но ничего, что я могу применить к моей ситуации. Разумеется, ссылки на соответствующие вопросы приветствуются.)
Вот иллюстрация того, что я пытаюсь сделать:
#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();
... думая, что я могу иметь "это", указывая на первый экземпляр в моем векторе. Здесь, где я в тупик.
Предложения оценены!
В С++ 11,
return { begin(vec), end(vec) };
преобразует вектор конкретных указателей в вектор абстрактного. Это так просто.
В С++ 03 вам придется явно вызвать конструктор и использовать .begin
вместо бесплатной функции.
Итератор литья, который принимает итераторы к конкретному и создает итераторы-абстрактные, может быть написан либо с помощью boost, либо вручную, а затем с диапазоном retired.
Тип, стирающий итераторы, чтобы они были просто "универсальными итераторами для abstract*
", может выполняться либо с повышением, либо без. Это добавляет накладные расходы (которые могут быть существенными, если их не делать осторожно), и их следует учитывать только в том случае, если указанные выше два варианта оказались проблематичными, и это продемонстрировано, чтобы устранить проблему в реальных тестах.
std::vector<Abstract*>
вместо std :: vector <Concrete *> `?children
не должны возвращатьconst&
?