Let's think about a possible implementation of CreateInfoObject
:
void InfoFactory::CreateInfoObject(AbstractInfo** info)
{
*info = new SuperInfo;
}
Now, SuperInfo
and MyInfoObject
do not have anything in common right ?
This is why, in general, the following is forbidden:
struct Base {};
struct D1: Base {};
struct D2: Base {};
int main(int argc, char* argv[])
{
Base** base = nullptr;
D1* d = nullptr;
base = d;
}
As it would allow D1
to point to something unrelated.
There are several solutions:
// 1. Simple
AbstractInfo* info = nullptr;
fc.CreateInfoObject(info);
// 2. Better interface
std::unique_ptr<AbstractInfo> info = fc.CreateInfoObject();
Then, if you know with certainty that you have, in fact, a MyInfoObject
you can use:
MyInfoObject* myInfo = static_cast<MyInfoObject*>(info);
or if you are unsure:
MyInfoObject* myInfo = dynamic_cast<MyInfoObject*>(info);
which will set myInfo
to nullptr
if ever the info
did not pointed to an instance of MyInfoObject
(or derived).
Bear in mind though, that your interface is really horrid. It very C-ish and it is unclear whether memory is actually allocated or not... and who is responsible for handling it if it is.
EDIT:
In good C++ style, we use RAII to both denote ownership and ensure clean-up. RAII is well-known though not very indicative, I myself prefer the newish SBRM (Scope Bound Resources Management).
The idea is that instead of using a bare pointer, which does not indicate anything about ownership (ie do you have to call delete on it ?) you should use a smart pointer, like for example unique_ptr
.
You can also make use of the return parameter of the method, to avoid having a two-steps initialization process (first create the pointer, then make it point to an object). Here is a concise example:
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
Here, there is no ambiguity in regard to the ownership.
Also, note how you better understand your question here:
std::unique_ptr<MyInfoObject> info = factory.CreateInfoObject();
would not compile because you cannot convert a AbstractInfo*
to a MyInfoObject*
without using static_cast
or dynamic_cast
.