У меня 3 класса B
, C
, D
, которые происходят от одного базового класса A
:
class A
{
// body
};
class B : public A
{
// body
};
class C : public A
{
// body
};
class D : public A
{
// body
};
Я хочу создать фабричную функцию, которая позволит мне создавать объекты определенного типа (B
, C
или же D
) и вернуть его как указатель на A
учебный класс:
typedef std::shared_ptr<A> a_ptr;
a_ptr createObject(int type)
{
switch(type)
{
case 0:
return a_ptr(new B());
break;
case 1:
return a_ptr(new C());
break;
case 2:
return a_ptr(new D());
break;
}
}
И тогда, если у меня есть, например, указатель типа B
Я хотел бы назначить B
объект, созданный фабрикой к нему. Единственное разумное решение для этого, которое пришло мне в голову, было бы:
std::shared_ptr<B> b = std::shared_ptr<B>(dynamic_cast<B*>(createObject(0)));
Но это выглядит некрасиво. Есть ли лучшее решение для этого? Или, может быть, я должен попробовать другой способ создания объектов с моей функцией?
Если вы хотите выполнить во время выполнения понижение shared_ptr
Скорее используйте std::dynamic_pointer_cast<>
:
std::shared_ptr<B> b = std::dynamic_pointer_cast<B>(createObject(0));
Если тип создаваемого объекта определяется во время выполнения, и ваш попытка проверить, имеет ли возвращаемый объект тип B
, тогда я не вижу лучшей альтернативы, чем динамический уныние.
С другой стороны, если вы знать с уверенностью 100% указанный объект имеет тип B
тогда вы могли бы использовать std::static_pointer_cast<>
:
std::shared_ptr<B> b = std::static_pointer_cast<B>(createObject(0));
В тот момент, когда вы знаете это со 100% уверенностью, я не понимаю, почему такая инструкция не должна стать:
std::shared_ptr<B> b = std::make_shared<B>();
Для небольшого количества «типов» ваш createObject выглядит не так уж плохо. Это только становится уродливым, если есть много «типов». Тогда вам будет лучше, если вы создадите табличное отображение типа для фабричной функции соответствующего класса. Например:
std::map<int, std::function <a_ptr ()> > dispatcherTable =
{
{0, createB },
{1, createC },
{2, createD }
};
Тогда вы можете просто использовать ваш тип в качестве индекса в таблице:
new_a = dispatcherTable[a]();
Эти «createB», «createC» и так далее могут быть статическими членами вашего фабричного класса или статическими членами классов B, C и так далее. В любом случае вы хотите это.