Calling methods based on derived type

F

flopbucket

Hi,

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.
 
V

Victor Bazarov

flopbucket said:
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 think that's the only way available. Wrap it in a function and you
are going to have a very clear and concise way. I would even create
some kind of table for either using in a 'switch' statement or for
dispatching the call (through a function pointer).
I was thinking I could do
something with templates and typeinfo?

I don't see how it's better. 'typeid' will give you the most derived
class. What if somebody derives something from 'C' (making 'CC' class)
so you won't be able to compare type_info for 'C' with it. 'dynamic_cast',
OTOH will definitely tell you whether the class is part of the hierarchy.
Any ideas? Please remember that I can not change the existing
classes.

I believe you'd be better off with dynamic_cast (or something based on
it).

V
 
V

Victor Bazarov

Gernot said:
Take a look at "virtual" keyword.

He is not allowed to change the classes, remember? Besides,
the classes are already polymorphic, otherwise he wouldn't
be talking of 'dynamic_cast'...
 
F

flopbucket

Take a look at "virtual" keyword.

virtual has nothing to do with his - the methods are NOT members of
the class, they are either stand alone functions of members of another
class. It is as if the calls need to be virtual based on the
parameter typeinfo and not the calling class pointer.
 
J

James Kanze

flopbucket said:
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.
 
R

Roland Pibinger

virtual has nothing to do with his - the methods are NOT members of
the class, they are either stand alone functions of members of another
class. It is as if the calls need to be virtual based on the
parameter typeinfo and not the calling class pointer.

I guess that you have written the processObject() functions. Your
difficulty exhibits a design problem rather than an implementation
problem. Your FactoryMethod returns a pointer to an interface (B). In
'classic' OOP style you are supposed to program against the interface,
not an implementation (C, D, E, ...). The problem can be solved by
either re-writing the processObject() functions to one function that
accepts the interface (processObject(B*)) or by writing special
factory methods for derived classes (e.g. FactoryMethodForC()) and
preserve the type information throughout the program. The latter is of
course 'less OO'.
 
F

flopbucket

I guess that you have written the processObject() functions. Your
difficulty exhibits a design problem rather than an implementation
problem. Your FactoryMethod returns a pointer to an interface (B). In
'classic' OOP style you are supposed to program against the interface,
not an implementation (C, D, E, ...). The problem can be solved by
either re-writing the processObject() functions to one function that
accepts the interface (processObject(B*)) or by writing special
factory methods for derived classes (e.g. FactoryMethodForC()) and
preserve the type information throughout the program. The latter is of
course 'less OO'.

Well, actually I didn't write either, but am tasked with glueing the
two together. The processObject() methods already exist from a legacy
application, and I need to call the correct one based on the object
created by the factory.
 
?

=?ISO-8859-15?Q?Juli=E1n?= Albo

Well, actually I didn't write either, but am tasked with glueing the
two together. The processObject() methods already exist from a legacy
application, and I need to call the correct one based on the object
created by the factory.

You can create a new hierarchy of classes, a base with all member functions
required in the original interface, and a processObject virtual member, and
derived classes with his own processObject member that call corresponding
the non-member processObject function. Then make a factory that return
object from this hierarchy that contains (or have a pointer, smart pointer,
whatever way you want) the corresponding object in the original hierarchy.
The drawback is that you have a lot of boring code to write.
 
J

James Kanze

You can create a new hierarchy of classes, a base with all member functions
required in the original interface, and a processObject virtual member, and
derived classes with his own processObject member that call corresponding
the non-member processObject function. Then make a factory that return
object from this hierarchy that contains (or have a pointer, smart pointer,
whatever way you want) the corresponding object in the original hierarchy.
The drawback is that you have a lot of boring code to write.

Not that much, really, since all you need is a template, and to
instantiate that. On the other hand, he will have to duplicate
whatever logic is currently present in SomeFactoryMethod for
choosing the type. If the logic is simple, and based on easily
available data, fine. If not, he may still need to call
SomeFactoryMethod, obtain whatever type, and then use a map to
determine which of his types he needs to create.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,770
Messages
2,569,586
Members
45,096
Latest member
ThurmanCre

Latest Threads

Top