Давайте подумаем о возможной реализации CreateInfoObject
:
void InfoFactory::CreateInfoObject(AbstractInfo** info)
{
*info = new SuperInfo;
}
Теперь, SuperInfo
и MyInfoObject
не имеют ничего общего, верно?
Поэтому вообще запрещено следующее:
struct Base {};
struct D1: Base {};
struct D2: Base {};
int main(int argc, char* argv[])
{
Base** base = nullptr;
D1* d = nullptr;
base = d;
}
Как это позволило бы D1
указать на что-то не связанное.
Существует несколько решений:
// 1. Simple
AbstractInfo* info = nullptr;
fc.CreateInfoObject(info);
// 2. Better interface
std::unique_ptr<AbstractInfo> info = fc.CreateInfoObject();
Тогда, если вы точно знаете, что у вас есть MyInfoObject
, вы можете использовать:
MyInfoObject* myInfo = static_cast<MyInfoObject*>(info);
или если вы не уверены:
MyInfoObject* myInfo = dynamic_cast<MyInfoObject*>(info);
, который установит myInfo
в nullptr
, если когда-либо info
не указывал на экземпляр MyInfoObject
(или производный).
Имейте в виду, что ваш интерфейс действительно ужасен. Это очень секретно, и неясно, выделена ли память на самом деле или нет ... и кто отвечает за ее обработку, если она есть.
EDIT
В хорошем стиле C ++ мы используем RAII как для обозначения владения, так и для обеспечения очистки. RAII хорошо известен, хотя и не очень показателен, я сам предпочитаю новый SBRM (Scope Bound Resources Management).
Идея состоит в том, что вместо использования пустого указателя, который ничего не указывает на владение (то есть вы должны вызывать delete на нем?), Вы должны использовать умный указатель , как например unique_ptr
.
Вы также можете использовать возвращаемый параметр метода, чтобы избежать двухэтапного процесса инициализации (сначала создайте указатель, а затем укажите его на объект). Вот краткий пример:
typedef std::unique_ptr<AbstractInfo> AbstractInfoPtr;
// Note: if you know it returns a MyInfoObject
// you might as well return std::unique_ptr<MyInfoObject>
AbstractInfoPtr InfoFactory::CreateInfoObject()
{
return AbstractInfoPtr(new MyInfoObject());
}
// Usage:
int main(int argc, char* argv[])
{
InfoFactory factory;
AbstractInfoPtr info = factory.CreateInfoObject();
// do something
} // info goes out of scope, calling `delete` on its pointee
Здесь нет никакой двусмысленности в отношении собственности.
Также обратите внимание, как вы лучше понимаете свой вопрос здесь:
std::unique_ptr<MyInfoObject> info = factory.CreateInfoObject();
не будет компилироваться, потому что вы не можете преобразовать AbstractInfo*
в MyInfoObject*
без использования static_cast
или dynamic_cast
.