(I propose a solution further ... bear with me ...)
One way to (almost) solve your problem is to use a visitor design template. Something like that:
class DrawVisitor { public: void draw(const Shape &shape);
Then instead:
Shape &shape = getShape(); // returns some Shape subclass shape.draw(); // virtual method
You would do:
DrawVisitor dv; Shape &shape = getShape(); dv.draw(shape);
Typically, in a visitor template, you implement the draw method as follows:
DrawVisitor::draw(const Shape &shape) { shape.accept(*this); }
But this only works if the Shape hierarchy was intended to be visited: each subclass implements a virtual accept method by calling the corresponding visitXxxx method for Visitor. Most likely, it was not intended for this.
Without the ability to change the class hierarchy to add a virtual accept method to Shape (and all subclasses), you will need another way to send the correct draw method. One naive principle is as follows:
DrawVisitor::draw(const Shape &shape) { if (const Square *pSquare = dynamic_cast<const Square *>(&shape)) { visitSquare(*pSquare); } else if (const Circle *pCircle = dynamic_cast<const Circle *>(&shape)) { visitCircle(*pCircle); }
This will work, but it uses the dynamic use of dynamic_cast. If you can afford this hit, this is a simple approach that is easy to understand, debug, maintain, etc.
Suppose that there is a list of all types of shapes:
enum ShapeId { SQUARE, CIRCLE, ... };
and there was a virtual method ShapeId Shape::getId() const = 0; so that each subclass redefines its ShapeId . You can then send your newsletter using the massive switch instead of if-elsif-elsif of dynamic_cast s. Or perhaps use a hash table instead of switch . The best scenario is to put this mapping function in one place so that you can identify multiple visitors without repeating the display logic every time.
So you probably don't have a getid() method. Very sorry. What is another way to get an identifier unique to each type of object? RTTI It is not necessarily elegant or reliable, but you can create a hash table with type_info pointers. You can build this hash table in some initialization code or build it dynamically (or both).
DrawVisitor::init() // static method or ctor { typeMap_[&typeid(Square)] = &visitSquare; typeMap_[&typeid(Circle)] = &visitCircle; // etc. } DrawVisitor::draw(const Shape &shape) { type_info *ti = typeid(shape); typedef void (DrawVisitor::*VisitFun)(const Shape &shape); VisitFun visit = 0; // or default draw method? TypeMap::iterator iter = typeMap_.find(ti); if (iter != typeMap_.end()) { visit = iter->second; } else if (const Square *pSquare = dynamic_cast<const Square *>(&shape)) { visit = typeMap_[ti] = &visitSquare; } else if (const Circle *pCircle = dynamic_cast<const Circle *>(&shape)) { visit = typeMap_[ti] = &visitCircle; } // etc. if (visit) { // will have to do static_cast<> inside the function ((*this).*(visit))(shape); } }
There may be some errors / syntax errors there, I have not tried compiling this example. I used to do something similar - the technique works. I'm not sure if you might run into problems with shared libraries.
The last thing I will add: no matter how you decide to send, it probably makes sense to make the base class of the visitor:
class ShapeVisitor { public: void visit(const Shape &shape);