Re: Calling methods based on derived type
flopbucket wrote:
Say I have a baseclass B that has many derived classes, let's say
C..Z, for example:
class B
{
};
class C : public B {};
class D : public B {};
class E : public B {};
...
Also assume that these classes are provided as is, that is, I can not
make any changes to them (the real classes contain many data members,
etc).
Now, there is a factory method that creates the correct class based on
input from some external source. Something like:
B *b = SomeFactoryMethod();
Of course SomeFactoryMethod will actually return any of the dervied
classes depending on the external information.
Now here is my question. There are a set of methods such as:
processObject(C *);
processObject(D *);
processObject(E *);
... for all derived types.
Given the base clas pointer returned from the factory, how can I call
the correct method? Obviously I can have a bunch of dynamic_cast<>'s
but that does not seem the best way. I was thinking I could do
something with templates and typeinfo?
Any ideas? Please remember that I can not change the existing classes.
If you cannot change the existing classes nor the factory
function, then you'll have to maintain a parallel hierarchy,
something like:
class AbstractObjectProcessor
{
public:
virtual ~AbstractObjectProcessor() {}
virtual void process( B* pObj ) const = 0 ;
} ;
template< typename T >
class ObjectProcessor : public AbstractObjectProcessor
{
public:
virtual void process( B* pObj ) const
{
assert( dynamic_cast< T* >( pObj ) != NULL ) ;
processObject( static_cast< T* >( pObj ) ) ;
}
} ;
Then, a static object for each type, and to find it:
struct TypeInfoCmp
{
bool operator()(
std::type_info const* lhs,
std::type_info const& rhs ) const
{
return lhs->before( *rhs ) ;
}
} ;
std::map< std::type_info const*,
AbstractObjectProcessor const*,
TypeInfoCmp > map ;
In such cases, I'll often add a constructor to the template:
template< typename T >
ObjectProcessor::ObjectProcessor()
{
map[ &typeid( T ) ] = this ;
}
Be careful about the order of initialization if you do this;
either the map must be wrapped in a singleton, or you'll have to
put all of the static instances in the same file, after the map.
To call the function, of course:
B* pB = SomeFactoryMethod() ;
map[ &typeid( *pB ) ]->process( pB ) ;
Note too that anytime someone adds a derived class, you'll have
to add a static ObjectProcessor object.
--
James Kanze (GABI Software) email:james.kanze@gmail.com
Conseils en informatique orient=E9e objet/
Beratung in objektorientierter Datenverarbeitung
9 place S=E9mard, 78210 St.-Cyr-l'=C9cole, France, +33 (0)1 30 23 00 34