В С++ предполагается следующая иерархия классов:
class BaseClass { };
class ChildClass : public BaseClass { };
Далее предположим фабричные классы для этих двух классов с общим шаблонным базовым классом:
template<typename T>
class Factory {
public:
virtual T* create() = 0;
};
class BaseClassFactory : public Factory<BaseClass> {
public:
virtual BaseClass* create() {
return new BaseClass(&m_field);
}
private:
SomeClass m_field;
};
class ChildClassFactory : public Factory<ChildClass> {
public:
virtual ChildClass* create() {
return new ChildClass(&m_field);
}
private:
SomeOtherClass m_field; // Different class than SomeClass
};
Обратите внимание, что размер/внутренняя структура ChildClassFactory
и BaseClassFactory
различны из-за их разных полей.
Теперь, если у меня есть экземпляр ChildClassFactory
(или Factory<ChildClass>
), могу ли я безопасно преобразовать его в Factory<BaseClass>
(через reinterpret_cast
)?
Factory<ChildClass>* childFactory = new ChildClassFactory();
// static_cast doesn't work - need to use reinterpret_cast
Factory<BaseClass>* baseFactory = reinterpret_cast<Factory<BaseClass>*>(childFactory);
// Does this work correctly? (i.e. is "cls" of type "ChildClass"?)
BaseClass* cls = baseFactory->create();
Я знаю, что не всегда можно приводить шаблонные классы таким образом, но в этом особом случае приведение должно быть безопасным, не так ли?
Я протестировал его с помощью Visual C++ 2010, и он работает. Теперь мой вопрос: можно ли это перенести на другие компиляторы?
Обновление: поскольку произошла некоторая путаница, позвольте мне пояснить еще, что (предположительно) важно в моем примере:
ChildClass
является дочерним классомBaseClass
- Пользователь
Factory<BaseClass>
не знает, какой дочерний классBaseClass
будет создан. Все, что он знает, это то, чтоBaseClass
создано. Factory<T>
не имеет собственных полей (кроме vtable).Factory::create()
isvirtual
BaseClassFactory
и вашиChildClassFactory
классы никак не связаны между собой. Кроме того, нет смысла иметь шаблонFactory<T>
, потому что каждый экземпляр шаблона представляет собой отдельный, не связанный тип, поэтому виртуальный интерфейс не дает вам вообще никакой выгоды. - person Kerrek SB   schedule 26.01.2012create()
разрешается во время выполнения с помощью vtable, это определенно дает мне что-то. Я могу передать экземпляр фабрики с типомFactory<BaseClass>
, и его пользователю не нужно знать, какой класс (кромеBaseClass
) фактически создан. - person Sebastian Krysmanski   schedule 26.01.2012T* t = new T; delete t; t->foo();
, и в настоящее время это работает на моем текущем компиляторе, значит ли это, что здесь тоже не может быть совершенно неправильно? - person PlasmaHH   schedule 26.01.2012Factory<T>
, и вы получите точно такое же поведение. - person Kerrek SB   schedule 26.01.2012create()
, не зная дочернего класса (например,ChildClassFactory
). Но это на самом деле то, что я хочу. Возможно, мне не стоило использовать пример, который так похож на хорошо известный шаблон проектирования. - person Sebastian Krysmanski   schedule 26.01.2012ChildClass
, у вас есть ровно один базовый класс для каждого производного класса, что несколько избыточно. Вы можете просто специализировать фабричный класс, если это все, что вам нужно, без использования дополнительного производного класса. - person Kerrek SB   schedule 26.01.2012