Поиграв с этим, я подозреваю, что это не возможно, но я думал, что попрошу экспертов. У меня есть следующий код на С++:
class IInterface { virtual void SomeMethod() = 0; }; class Object { IInterface* GetInterface() { ... } }; class Container { private: struct Item { Object* pObject; [... other members ...] }; std::list<Item> m_items; };
Я хочу добавить эти методы в контейнер:
MagicIterator<IInterface*> Begin(); MagicIterator<IInterface*> End();
Чтобы абоненты могли писать:
Container c = [...] for (MagicIterator<IInterface*> i = c.Begin(); i != c.End(); i++) { IInterface* pItf = *i; [...] }
Таким образом, по существу, я хочу предоставить класс, который, по-видимому, выполняет итерацию по какой-либо коллекции (которую вызывающий объект Begin() и End() не может видеть) указателей IInterface, но который фактически выполняет итерацию по набору указатели на другие объекты (частные для класса Container), которые могут быть преобразованы в указатели IInterface.
Несколько ключевых моментов:
-
MagicIterator
определяется внеContainer
. -
Container::Item
должен оставаться закрытым.
-
MagicIterator
должен перебирать указателиIInterface
, несмотря на то, чтоContainer
содержит astd::list<Container::Item>
.Container::Item
содержитObject*
, аObject
можно использовать для извлеченияIInterface*
.
-
MagicIterator
должен быть повторно использован несколькими классами, которые напоминают Контейнер, но могут внутренне иметь разные реализации списков, содержащих разные объекты (std::vector<SomeOtherItem>
,mylist<YetAnotherItem>
) иIInterface*
, полученные разными способами каждый раз.
-
MagicIterator
не должен содержать код, специфичный для контейнера, хотя он может делегировать классы, которые делают, если такое делегирование не жестко закодировано для конкретных контейнеров внутриMagicIterator
(так или иначе, как это разрешено автоматически компилятором, например).
- Решение должно компилироваться в Visual С++ без использования других библиотек (например, boost), для чего требуется лицензионное соглашение от их авторов.
- Кроме того, итерация может не выделять кучную память (поэтому no
new()
илиmalloc()
на любом этапе), а неmemcpy()
.
Спасибо за ваше время, даже если вы просто читаете; это действительно меня раздражало!
Обновление: Пока у меня были очень интересные ответы, ни один из них не удовлетворял всем вышеперечисленным требованиям. Примечательно, что сложными областями являются: i) развязка MagicIterator из Container каким-то образом (аргументы шаблона по умолчанию не разрезают его) и ii) избегают распределения кучи; но я действительно получаю решение, которое охватывает все вышеперечисленные пули.