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 Squares and Circles with DrawableSquares and DrawableCircles, respectively.
Is that the best way to accomplish this, or is there something better (preferably something that leaves the creation of Squares and Circles intact).
Thanks in advance.
(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
drawmethod like this:But that only works if the
Shapehierarchy was designed to be visited: each subclass implements the virtual methodacceptby calling the appropriatevisitXxxxmethod on the Visitor. Most likely it was not designed for that.Without being able to modify the class hierarchy to add a virtual
acceptmethod toShape(and all subclasses), you need some other way to dispatch to the correctdrawmethod. 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 massiveswitchstatement instead of the if-elsif-elsif ofdynamic_casts. Or perhaps instead of aswitchuse 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_infopointers. 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: