Let's say we already have a hierarchy of classes, e.g.
class Shape { virtual void get_area() = 0; };
class Square : Shape { ... };
class Circle : Shape { ... };
etc.
Now let's say that I want to (effectively) add a virtual draw() = 0
method to Shape
with appropriate definitions in each sub-class. However, let's say I want to do this without modifying those classes (as they are part of a library that I don't want to change).
What would be the best way to go about this?
Whether or not I actually "add" a virtual
method or not is not important, I just want polymorphic behaviour given an array of pointers.
My first thought would be to do this:
class IDrawable { virtual void draw() = 0; };
class DrawableSquare : Square, IDrawable { void draw() { ... } };
class DrawableCircle : Circle, IDrawable { void draw() { ... } };
and then just replace all creations of Square
s and Circle
s with DrawableSquare
s and DrawableCircle
s, respectively.
Is that the best way to accomplish this, or is there something better (preferably something that leaves the creation of Square
s and Circle
s intact).
Thanks in advance.
One 'off the wall' solution you might like to consider, depending on the circumstance, is to use templates to give you compile time polymorphic behaviour. Before you say anything, I know that this will not give you traditional runtime polymorphism so it may well not be useful but depending on the limitations of the environment in which you're working, it can prove useful:
The
drawIt()
method is probably the key thing here as it represents generic behaviour for any class meeting the requirement of having adraw()
method. Do watch out for code bloat here though as the compiler will instantiate a separate method for each type passed.This can be useful in situations where you need to write one function to work on many types which have no common base class. I'm aware that this is not the question you asked, but I thought I'd throw it just as an alternative.
(I do propose a solution down further... bear with me...)
One way to (almost) solve your problem is to use a Visitor design pattern. Something like this:
Then instead of this:
You would do:
Normally in a Visitor pattern you would implement the
draw
method like this:But that only works if the
Shape
hierarchy was designed to be visited: each subclass implements the virtual methodaccept
by calling the appropriatevisitXxxx
method on the Visitor. Most likely it was not designed for that.Without being able to modify the class hierarchy to add a virtual
accept
method toShape
(and all subclasses), you need some other way to dispatch to the correctdraw
method. One naieve approach is this:That will work, but there is a performance hit to using dynamic_cast that way. If you can afford that hit, it is a straightforward approach that is easy to understand, debug, maintain, etc.
Suppose there was an enumeration of all shape types:
and there was a virtual method
ShapeId Shape::getId() const = 0;
that each subclass would override to return itsShapeId
. Then you could do your dispatch using a massiveswitch
statement instead of the if-elsif-elsif ofdynamic_cast
s. Or perhaps instead of aswitch
use a hashtable. The best case scenario is to put this mapping function in one place, so that you can define multiple visitors without having to repeat the mapping logic each time.So you probably don't have a
getid()
method either. Too bad. What's another way to get an ID that is unique for each type of object? RTTI. This is not necessarily elegant or foolproof, but you can create a hashtable oftype_info
pointers. You can build this hashtable in some initialization code or build it dynamically (or both).Might be some bugs/syntax errors in there, I haven't tried compiling this example. I have done something like this before -- the technique works. I'm not sure if you might run into problems with shared libraries though.
One last thing I'll add: regardless of how you decide to do the dispatch, it probably makes sense to make a visitor base class:
What you're describing is somewhat like the decorator pattern. Which is very suitable to change runtime behaviour of existing classes.
But I don't really see how to implement your practical example, if shapes have no way to be drawn, then there's no way to change drawing behaviour at runtime either...
But I suppose this is just a very simplified example for stackoverflow? If all the basic building blocks for the desired functionality are available, then implementing the exact runtime behaviour with such a pattern is certainly a decent option.