c++ factory and casting issue
I have a project where I have a lot of related Info classes and I was considering putting up a hierarchy by having a AbstractInfo class and then a bunch of derived classes, overriding the implementations of AbstractInfo as necessary. However it turns out that in C++ using the AbstractInfo class to then create one of the derived objects is not that simple. (see this question, comment on last answer)
I was going to create like a factory class which creates an Info object and always returns an AbstractInfo object. I know from C# you can do that with interfaces, but in C++ things are a little different it seems.
Down casting becomes a complicated affair and it seems prone to error.
Does anyone have a better 开发者_StackOverflowsuggestion for my problem?
You don't require downcasting. See this example:
class AbstractInfo
{
public:
virtual ~AbstractInfo() {}
virtual void f() = 0;
};
class ConcreteInfo1 : public AbstractInfo
{
public:
void f()
{
cout<<"Info1::f()\n";
}
};
class ConcreteInfo2 : public AbstractInfo
{
public:
void f()
{
cout<<"Info2::f()\n";
}
};
AbstractInfo* createInfo(int id)
{
AbstractInfo* pInfo = NULL;
switch(id)
{
case 1:
pInfo = new ConcreteInfo1;
break;
case 2:
default:
pInfo = new ConcreteInfo2;
}
return pInfo;
}
int main()
{
AbstractInfo* pInfo = createInfo(1);
pInfo->f();
return 0;
}
Don't downcast - use virtual methods. Just return the pointer to a base class from the factory and only work through that pointer.
class AbstractInfo
{
public:
virtual ~AbstractInfo();
virtual X f();
...
};
class Info_1 : public AbstractInfo
{
...
};
class Info_2 : public AbstractInfo
{
...
};
AbstractInfo* factory(inputs...)
{
if (conditions where you would want an Info_1)
return new Info_1(...);
else if (condtions for an Info_2)
return new Info_2(...);
else
moan_loudly();
}
If you don't want the factory method to become a single point of maintenance as downstream client code adds Info types, you can instead provide some mechanism for client code to register methods for creation of those derived objects. Check out the Gang of Four's Design Patterns book for creational patterns, or google them.
While generally you can't overload on return types in C++, there is an exception for covariant return types
Example taken from wikipedia:
// Classes used as return types:
class A {
}
class B : public A {
}
// Classes demonstrating method overriding:
class C {
A* getFoo() {
return new A();
}
}
class D : public C {
B* getFoo() {
return new B();
}
}
Thus eliminating the need for casting.
C++ provides polymorphism just as C# does. The language has no special interface-type, but you can emulate that by using a class that only has pure virtual methods. In C# all methods are virtual by default (meaning they are bound at runtime), whereas in C++ you have to declare that explicitly using the virtual
-keyword. Also, C# handles all objects using references (as far as I know), whereas in C++ you have to choose between values, pointers or references. In your case, you most likely want your factory to return a pointer to the interface, or even better a smart pointer, so you don't have to worry about memory management.
To elaborate / pontificate a little, the "good" time to use an abstract interface (eg: base class with virtual functions) is when substantially all the functionality which will be used on the objects can be contained in virtual functions. If that's the case, you can do what you're proposing easily, and just call the virtual functions on the base class pointer, which will automatically call the most-derived version provided.
If you find yourself needing to downcast often to get at child-class specific functions/data, this approach is probably not optimal for your situation. In that case you may find yourself writing some of the functionality outside the classes, providing multiple implementations for each type, and using some sort of RTTI to help downcast as necessary. This is more messy, but tends to be more common outside of the "academic" or well-isolated usages.
Looks like you've got a lot of good info/advice here in the other answers, though.
精彩评论