Base class handle to child class instance. Is there an elegant way to get the child class type at runtime?
This is h开发者_如何学Goow I do it currently:
ref class Base abstract {};
ref class ConcreteClass1 : public Base {};
ref class ConcreteClass2 : public Base {};
(...and even more...)
void DoStuff(Base ^base)
{
System::Type ^type = base->GetType();
System::String ^name = type->Name;
if(name == "ConcreteClass1")
DoOtherStuff((ConcreteClass1 ^) base);
else if(name == "ConcreteClass2")
DoOtherStuff((ConcreteClass2 ^) base);
(...and even more...)
}
Is there a more "elegant" way to do this?
With my approach, I have to add a new else if for every new Concrete Class, which makes me feel like one of the examples on thedailywtf.com.
Well, one simple thing you could do to make this more elegant would be to compare the types directly instead of using strings and type names:
void DoStuff(Base ^base)
{
System::Type ^type = base->GetType();
if(type == ConcreteClass1::typeid)
DoOtherStuff((ConcreteClass1 ^) base);
else if(type == ConcreteClass2::typeid)
DoOtherStuff((ConcreteClass2 ^) base);
(...and even more...)
}
However, this has quite a bit of "code smell" to it. Typically, the entire point of using abstract classes is to allow for polymorphism - if you can make DoOtherStuff a virtual function on each type, you could just do:
base->DoOtherStuff();
And the appropriate method will get called for you...
It is more elegant if your design confines all the knowledge about what makes a ConcreteClass1
special inside ConcreteClass1
. Could you have a Process()
function in the base class that they each inherit from the base, and have it just do whatever your if bodies would do, including calling DoOtherStuff(this)
? That would have better encapsulation, and when you added more classes you wouldn't change your calling code, because it would just be calling base->Process()
and relying on polymorphism.
A better design than if statements, I find, is to use a dispatch table -- essentially a Dictionary from 'type' to function pointer / delegate. If the child class is responsible for registering itself to the table, then your dispatch function is simply something like :
void DoStuff(Base ^base)
{
System::Type ^type = base->GetType();
m_DispatchTable[type](base);
}
and to add a new dispatch, it just needs to register itself in the table - no code updating required. This avoids maintaining the 'if' aggregate, and if you ever need to call more than one function you can make your dispatch table map to a more complex type.
精彩评论