У меня есть базовый класс, представляющий элемент с некоторыми общими свойствами (имя, несколько флагов и т. Д.):
class AbstractItem;
class MacroDefinition : public AbstractItem;
У меня также есть шаблонизированный класс, который управляет коллекциями этих элементов, также заботясь о них.общих функций, таких как загрузка их из файлов XML на диск:
template <class ItemT>
class AbstractItemManager
{
public:
AbstractItemManager();
ItemT* GetAt(int index);
vector<ItemT*> Get(...);
private:
vector<ItemT*> mItems;
};
Для любого данного типа AbstractItem
я могу создать класс менеджера этого подходящего типа, обработать базовую функциональность для меня изатем функциональность слоя, относящаяся к этому типу, поверх этого:
class MacroManager : public AbstractItemManager<MacroDefinition>
{
public:
MacroManager():AbstractItemManager<MacroDefinition>();
};
Тот факт, что класс менеджера принимает тип элемента в качестве параметра шаблона, означает, что я могу совершать подобные вызовы, как в MacroManager, так и извне,и получать предметы соответствующего типа без необходимости слепо разыгрывать указатели повсюду.
MacroManager* macroManager = new MacroManager();
Macro* macro = macroManager->GetAt(2);
Теперь я реализую другой класс.Я хочу иметь возможность передать ему ссылку на AbstractItemManager
, чтобы я мог получить доступ к списку элементов в любом данном классе менеджера.Однако мне нужно, чтобы компилятор понял, что ItemT
всегда будет производным от AbstractItem
.Я хотел бы иметь возможность сделать что-то вроде этого:
class FavoriteAbstractItemList
{
public:
FavoriteAbstractItemList(AbstractItemManager* manager)
:mManager(manager)
{
vector<AbstractItem*> items = mManager->Get(...);
...
}
private:
AbstractItemManager* mManager;
};
Следовательно:
FavoriteAbstractItemList* list = new FavoriteAbstractItemList(macroManager);
Конечно, это неверно, потому что я не предоставляю аргумент шаблона дляAbstractItemManager
когда я использую его в FavoriteAbstractItemList
.Поскольку у моих подклассов менеджера (MacroManager
и т. Д.) Есть все разные типы ItemT
, я застрял здесь.
Я представляю, что мог бы немного изменить свою иерархию классов, и это сработало бы:
template<class ItemT>
class AbstractItemManager_Base;
class AbstractItemManager : public AbstractItemManager_Base<AbstractItem>;
class MacroManager : public AbstractItemManager;
Но тогда аргумент шаблона ItemT
будет установлен в камне как AbstractItem
в MacroManager
и т. Д., Поэтому мне придется явно привести все элементы в пределах MacroManager
к Macro
ипозаботьтесь о том, чтобы к нему были добавлены только элементы типа Macro
.
Похоже, что это, вероятно, распространенная проблема, но не та, которая имеет прямой ответ.У меня не так уж много практического опыта работы с шаблонами C ++, поэтому я был бы очень признателен за то, чтобы разобраться в этом вопросе.Учитывая компромиссы, которые я представил, каков наиболее разумный способ достичь того, что я ищу?Или я начинаю с неправильного подхода?
Спасибо за все ваши полезные ответы.Я закончил тем, что пошел с решением, которое вы оба предложили.Мне не приходило в голову, что я мог бы использовать тип шаблона для переопределения уже определенного базового типа, но к тому времени я привык к компиляции шаблонов C ++ во время компиляции.
Что касаетсявекторная проблема, к сожалению, но я закончил тем, что выбрал одно из предложенных решений и создал отдельный метод в шаблонном классе, который вызывает исходный метод и помещает все в новый vector<ItemT*>
с кучей статических приведений.Я уверен, что это добавляет немного накладных расходов, но это все же гораздо более элегантно, чем мое коленное решение полностью отказаться от шаблонов.Единственное, что я действительно теряю, - это возможность напрямую перебирать mItems
в подклассах без приведения от AbstractItem*
до Macro*
(и т. Д.), Но я, безусловно, могу с этим справиться.
Вотновая иерархия классов, по сути:
class AbstractItemManager
{
public:
virtual AbstractItem* GetAt(int index);
vector<AbstractItem*> Get(...);
protected:
vector<AbstractItem*> mItems;
};
template <class ItemT>
class TemplatizedItemManager : public AbstractItemManager
{
public:
virtual ItemT* GetAt(int index);
std::vector<ItemT*> GetItems(...);
};
class MacroManager : public TemplatizedItemManager<Macro>;
Еще раз спасибо!