Avoiding performance concerns of Runtime Polymorphism - c++

In a numerical code run on thousands of processors for 10s of hours, I have a base class (Mesh) whose methods are hit 100s to 1000s of millions of times. There are currently two (Mesh_A, Mesh_B) derived classes, but eventually this will expand to three or four. User code cannot know until runtime whether its pointer to Mesh is actually a Mesh_A or Mesh_B, but for the rest of the run, it never changes.
Current Implementation:
// Base class
class Mesh {
...
virtual const Point& cell_centroid(int c) = 0;
}
// derived class A
class MeshA : public Mesh {
...
Point& cell_centroid(int c) { return cell_centroids_[c]; }
}
// derived class B
class MeshB : public Mesh {
...
Point& cell_centroid(int c) { return other_framework_->cell_centroid(c); }
}
// typical user class
class User {
User(Mesh* mesh) : mesh_(mesh) {}
void evalFunction() {
for (int c=0; c!=mesh_->num_cells(); ++c) {
double result = func(mesh_->cell_centroid(c));
...
}
}
// Other methods which use mesh_->cell_centroid() very often, and in different ways.
}
Previously, MeshA was the only Mesh, and there was no base class, and the heavily hit methods were all inlined. Profiling shows that the change to runtime polymorphism (likely thanks to the loss of inlining?) with virtual methods has resulted in a ~15% hit, which just isn't going to fly.
I've been pouring over static polymorphism and other ideas, but I'd love to hear thoughts on how one might avoid this hit in a reasonably sustainable way.
Idea 1: Coarsen the virtual function to amortize overhead. One thought was to try to encapsulate all the "calling patterns" of these methods inside a virtual method, lifting the virtual to a coarser level while keeping the fine-grained methods as non-virtual. For example, in the above example, one could pass a function pointer to a new virtual method of Mesh that implemented the loop, returning an array of doubles and called a non-virtual, inlined cell_centroid() method inside of this.
// Base class
class Mesh {
...
virtual void evalFunction(double (*func)(Point&), std::vector<double>* result) = 0;
}
// derived class A
class MeshA : public Mesh {
...
void evalFunction(double (*func)(Point&), std::vector<double>* result) {
for (int c=0; c!=num_cells(); ++c) (*result)[c] = (*func)(cell_centroid(c));
}
Point& cell_centroid(int c) { return cell_centroids_[c]; }
}
// similar for B
// typical user class
class User {
User(Mesh* mesh) : mesh_(mesh) {}
void evalFunction() {
m_->evalFunction();
}
}
I'm a little nervous that this will make the Mesh interface huge -- I don't have a single access pattern (like the example) that could easily be encapsulated. My guess is that, for every virtual method in the current Mesh class (15-20), I'd have 3 or 4 different "calling patterns", and the interface for Mesh would explode. There are a variety of "User" classes and, while the sometimes use Mesh the same way, they don't always, and I don't want to limit myself to a few patterns.
Idea 2: Template all user code with Mesh_T. Write a factory that creates User<MeshA> or User<MeshB> instances depending upon runtime information. This is a little concerning because this will effectively mean that my entire code is templated code, compile times will blow up, errors will be harder to debug etc. A large code base would be touched.
Idea 3: It seems to me that one ought to be able to resolve, at the start of the run, that the Mesh pointer User gets is actually a MeshA or MeshB, and not need to do the virtual table lookups and regain the inlined A or B implementation. I don't know of an elegant way of doing this that wouldn't basically be worse than Idea 1, i.e. a bunch of duplicated code in User with case/switch. But if there were an elegant way of doing this, it would be my first choice.
Any thoughts on a good choice, a better idea, or other comments on runtime polymorphism of a high level class without virtual low-level methods would be appreciated!

Provided I understood you correctly that mesh_ will always be either MeshA or MeshB and not a mix of them.
// typical user class
class User {
User(Mesh* mesh) : mesh_(mesh) {}
template<class dType>
void evalFunction() {
dType *myMesh = dynamic_cast<dType *>(mesh_);
for (int c=0; c!=myMesh _->num_cells(); ++c) {
double result = func(myMesh _->cell_centroid(c));
...
}
}
void evalFunction() {
if (dynamic_cast<MeshA *>(mesh_))
evalFunction<MeshA>();
if (dynamic_cast<MeshB *>(mesh_))
evalFunction<MeshB>();
}
}
evalFunction chooses either A or B template.
Alternatively
class User {
User(Mesh* mesh) : mesh_(mesh) {}
template<class dType>
void evalFunction(dType *myMesh) {
for (int c=0; c!=myMesh _->num_cells(); ++c) {
double result = func(myMesh _->cell_centroid(c));
...
}
}
void evalFunction() {
MeshA *meshA = dynamic_cast<MeshA *>(mesh_);
if (meshA)
evalFunction<MeshA>(meshA);
MeshB *meshB = dynamic_cast<MeshB *>(mesh_);
if (meshB)
evalFunction<MeshB>(meshB);
}
}

Related

Advice for best approach at extending class capability

I want to extend a class to include extra data and capabilities (I want polymorphic behavior). It seemed obvious to use inheritance and multiple inheritance.
Having read various posts that inheritance (and especially multiple inheritance) can be problematic, I've begun looking into other options:
Put all data and functions in one class and not use inheritance
Composite pattern
mixin
Is there a suggested approach for the following inheritance example? Is this a case where inheritance is reasonable? (but I don't like having to put default functions in the base-class)
#include <iostream>
//================================
class B {
public:
virtual ~B() { }
void setVal(int val) { val_ = val; }
// I'd rather not have these at base class level but want to use
// polymorphism on type B:
virtual void setColor(int val) { std::cout << "setColor not implemented" << std::endl; }
virtual void setLength(int val) { std::cout << "setLength not implemented" << std::endl; }
private:
int val_;
};
//================================
class D1 : virtual public B {
public:
void setColor(int color) {
std::cout << "D1::setColor to " << color << std::endl;
color_ = color;
}
private:
int color_;
};
//================================
class D2 : virtual public B {
public:
void setLength(int length) {
std::cout << "D2::setLength to " << length << std::endl;
length_ = length;
}
private:
int length_;
};
//================================
// multi-inheritance diamond - have fiddled with mixin
// but haven't solved using type B polymorphically with mixins
class M1 : public D1, public D2 {
};
//================================
int main() {
B* d1 = new D1;
d1->setVal(3);
d1->setColor(1);
B* m1 = new M1;
m1->setVal(4);
m1->setLength(2);
m1->setColor(4);
return 0;
}
Suspected problems with the original example code
There are a number of issues with your example.
In the first place, you don't have to supply function bodies in the base class. Use pure virtual functions instead.
Secondly, both your classes D1 and D2 miss functionality, so they should be abstract (which will prevent you from creating deprived objects from them). This second issue will become clear if you indeed use pure virtual functions for your base class. The compiler will start to issue warnings then.
Instantiating D1 as you do with new D1, is bad design, because D1 has no truly functional implementation of the setLength method, even if you give it a 'dummy' body. Giving it a 'dummy' body (one that doesn't do anything useful) so masks your design error.
So your remark (but I don't like having to put default functions in the base-class) testifies of a proper intuition. Having to do that signals flawed design. A D1 object cannot understand setLength, while its inherited public interface promises it can.
And: There's nothing wrong with multiple inheritance, if used correctly. It is very powerful and elegant. But you have to use it where appropiate. D1 and D2 are partial implementations of B, so abstract, and inheriting from both will indeed give you a complete implementation, so concrete.
Maybe a good rule to start with is: Use multiple inheritance only if you see a compelling need for it. But if you do, as said, it's very useful. It can prevent quite some ugly asymmetry and code duplication, compared to e.g. a language like Java, that has banned it.
I am not a tree doctor. When I use a chainsaw I endanger my leg. But that is not to say chainsaws ain't useful.
Where to put the dummy: Nowhere please, do not disinherit...
[EDIT after first comment of OP]
If you derive a class D1 from B that would print 'setLength not implemented' if you call its setLength method, how should the caller react? It shouldn't have called it in the first place, which the caller could have known if D1 did not derive from a B that has this methods, pure virtual or not. Then it would have been clear that it just doesn't support this method. Having the B baseclass makes D1 feel at home in a polymorphic datastructure who'se element type, B* or B&, promises its users that its objects properly support getLength, which they don't.
While this is not the case in your example (but maybe you left things out), there may of course be a good reason to derive D1 and D2 from B. B could hold a part of the eventual interface or implementation of its derived classes that both D1 an D2 need.
Suppose B had a method setAny (key, value) (setting a value in a dictionary), which D1 and D2 both use, D1 calls it in setColor and D2 calls it in setLength.
In that case use of a common base class is justified. In that case B should not have virtual methods setColor or setLength at all, neither dummies nor pure. You should just have a setColor in your D1 class and a setLength in your D2 class, but neither of both in your B class.
There's a basic rule in Object Oriented Design:
Do not disinherit
By introducing the concept of a "method that's not applicable" in a concrete class that's just what you're doing. Now rules like this aren't dogma's. But violating this rule almost always points to a design flaw.
All B's in one datastructure is only useful to have them do a trick that they all understand...
[EDIT2 after second coment of OP]
OP wants to have a map that can hold objects of any class derived from B.
This is exactly where the problem starts. To find out how to store pointers and references to our objects, we have to ask: what is the storage used for. If a map, say mapB is used to store pointers to B, there must be some point in that. With data storage the fun is in retrieving the data and doing something useful with it.
Let's make this a bit simpler by working with lists from everyday life. Suppose I have a personList of say 1000 persons, each with their fullName and phoneNumber. And now say I have a problem with the kitchen sink. I could in fact read through the list, call every single Person on it and ask: can you repair my kitchen sink. In other words: do you support the repairKitchenSink method. Or: are you by any chance an instance of class Plumber (are you a Plumber). But then I spend quite some time calling, and maybe after 500 calls or so, I'll be lucky.
Now all 1000 persons on my personList do support the talkToMe method. So whenever I feel lonely I can call any person from that list and invokate that Person's talkToMe method. But they should not all have a repairKitchenSink method, even not a pure virtual or a dummy variation that does something else, because if I would call this method for a person of class Burglar, he'd probably respond to the call, but in an unexpected way.
So class Person shouldn't contain a method repairKitchenSink, even not a pure virtual one. Because it should never called as part of iteration of personList. It should be called when iterating plumberList. This lists only holds objects that support the repairKitchenSink method.
Use pure virtual functions only where appropriate
They may support it in different ways though. In other words, in class Plumber, method repairKitchenSink can e.g. be pure virtual. There may e.g. be 2 derived classes, PvcPlumber and CopperPlumber. CopperPlumber would implement (code) the repairKitchenSink method by calling lightFlame, followed by a call to solderDrainToSink whereas PvcPlumber would implement it as successive calls to applyGlueToPvcTube and glueTubeToSinkOutlet. But both plumber subclasses implement repairKitchenSink, only in different ways. This and only this justifies having the pure virtual function repairKitchenSink in their base class Plumber. Now of course a class may be derived from Plumber that doesn't implement that method, say class WannabePlumber. But since it will be abstract, you cannot instantiate objects from it, which is good, unless you want wet feet.
There may be many different subclasses of Person. They e.g. represent different professions, or different political preferences, or different religions. If a Person is a Democrat Budhist Plumber, than he (M/F) may be in a derived class that inherits from classes Democrat, Budhist and Plumber. Using inheritance or even typing for something so volatile as political preferences or religious beliefs, or even profession and the endless amount of combinations of those, would not be handy in practice, but it's just an example. In reality profession, religion and politicalPreference would probably be attributes. But that doesn't change the point that matters here. IF something is of a class does not support a certain operation, THEN it shouldn't be in a datastructure that suggests it does.
By, besides personList, having plumberList, animistList and democratList, you're sure to call a person that understands your call to method inviteBillToPlayInMyJazzBand, or worshipTheTreeInMyBackyard.
Lists don't contain objects, they only contain pointers or references to objects. So there's nothing wrong with our Democratic Budhist Plumber being contained in personList, democratList, budhistList and plumberList. Lists are like database indexes. The don't contain the records, they just refer to them. You can have many indexes on one table, and you should, because indexes are small and make your database fast.
The same holds for polymorphic datastructures. At the moment that even personList, democratList, budhistList and plumberList become so large that you're running out of memory, the solution is generally NOT to only have a personList. Because then you exchange your memory problem for a perfomance problem and a code complexity problem that, in general, is far worse.
So, back to your comment: You say you want all your derived classes to be in a list of B's. Fine, but still the interface of a B should only contain methods that are implemented for everything in the list, so no dummy methods. That would be like going through the library and going through all books, in search for one that supports the teachMeAboutTheLovelifeOfGoldfishes method.
To be honest, in telling you all this, I've been committing a capital sin. I've been selling general truths. But in software design these don't exist. I've been trying to sell them to you because I've been teaching OO design for some 30 years now, and I think I recognize the point where your stuck. But to every rule there are many exceptions. Still, if I've properly fathomed your problem, in this case I think you should go for separate datastructures, each holding only references or pointers to objects that really can do trick that you were after when you iterated through that particular datastructure.
A point is a square circle
Part of the confusion in properly using polymorphic datastructures (datastructures holding pointers or references to different object types) comes for the world of relational databases. RDB's work with tables of flat records, each record having the same fields. Since some fields may not apply, something called 'constraint' was invented. In C++ class Point would contain field x and y. Class Circle could inherit from it and additionally contain field 'radius'. Class Square could also inherit from Point, but contain field 'side' in addition to x and y. In the RDB world constraints, not fields, are inherited. So a Circle would have constraint radius == 0. And a Square would have constraint side == 0. And a Point would inherit both constraints, so it would meet the conditions for both being a square and a circle: A point is a square circle, which in mathematics indeed is the case. Note that the constraint inheritance hierarchy is 'upside down', compared to C++. Which can be confusing.
What doesn't help either is the generally held belief that inheritance goes hand in hand with specialization. While this is often the case it isn't always. In many cases in C++ inheritance is extension rather than specialization. The two often coincide, but the Point, Square, Circle example shows that this isn't a general truth.
If inheritance is used, in C++ Circle should derive from Point, since it has extra fields. But a Circle certainly isn't a special type of Point, it's the other way round. In many practical libraries, by the way, Circle will contain an object of class Point, holding x and y, rather than inherit from it, bypassing the whole problem.
Welcome to the world of design choices
What you bumped into is a real design choice, and an important one. Thinking very carefully about things like this, as you are doing, and trying them all in practice, including the allegedly 'wrong' ones, will make you a programmer, rather than a coder.
Let me first state that what you are trying to do is a design smell: Most probably what you are actually trying to achieve could be achieved in a better way. Unfortunately we can't know what it is you actually want to achieve since you only told us how you want to achieve it.
But anyway, your implementation is bad, as the methods report "not implemented" to the users of the program, rather than to the caller. There is no way for the caller to react on the method not doing what is intended. Even worse, you don't even output it to the error stream, but to the regular output stream, so if you use that class in any program that produces regular output, that output will be interrupted by your error message, possibly confusing a program further on in a pipeline).
Here's a better way to do it:
#include <iostream>
#include <cstdlib> // for EXIT_FAILURE
//================================
class B {
public:
virtual ~B() { }
void setVal(int val) { val_ = val; }
// note: No implementation of methods not making sense to a B
private:
int val_;
};
//================================
class D1 : virtual public B {
public:
void setColor(int color) {
std::cout << "D1::setColor to " << color << std::endl;
color_ = color;
}
private:
int color_;
};
//================================
class D2 : virtual public B {
public:
void setLength(int length) {
std::cout << "D2::setLength to " << length << std::endl;
length_ = length;
}
private:
int length_;
};
class M1 : public virtual D1, public virtual D2 {
};
//================================
int main() {
B* d1 = new D1;
p->setVal(3);
if (D1* p = dynamic_cast<D1*>(d1))
{
p->setColor(1);
}
else
{
// note: Use std::cerr, not std::cout, for error messages
std::cerr << "Oops, this wasn't a D1!\n";
// Since this should not have happened to begin with,
// better exit immediately; *reporting* the failure
return EXIT_FAILURE;
}
B* m1 = new M1;
m1->setVal(4);
if (D2* p = dynamic_cast<D2*>(m1))
{
p->setLength(2);
}
else
{
// note: Use std::cerr, not std::cout, for error messages
std::cerr << "Oops, this wasn't a D1!\n";
// Since this should not have happened to begin with,
// better exit immediately; *reporting* the failure
return EXIT_FAILURE;
}
if (D1* p = dynamic_cast<D1*>(m1))
{
p->setColor(4);
}
else
{
// note: Use std::cerr, not std::cout, for error messages
std::cerr << "Oops, this wasn't a D1!\n";
// Since this should not have happened to begin with,
// better exit immediately; *reporting* the failure
return EXIT_FAILURE;
}
return 0;
}
Alternatively, you could make use of the fact that your methods share some uniformity, and use a common method to set all:
#include <iostream>
#include <stdexcept> // for std::logic_error
#include <cstdlib>
#include <string>
enum properties { propValue, propColour, propLength };
std::string property_name(property p)
{
switch(p)
{
case propValue: return "Value";
case propColour: return "Colour";
case propLength: return "Length";
default: return "<invalid property>";
}
}
class B
{
public:
virtual ~B() {}
// allow the caller to determine which properties are supported
virtual bool supportsProperty(property p)
{
return p == propValue;
}
void setProperty(property p, int v)
{
bool succeeded = do_set_property(p,v);
// report problems to the _caller_
if (!succeeded)
throw std::logic_error(property_name(p)+" not supported.");
}
private:
virtual bool do_set_property(property p)
{
if (p == propValue)
{
value = v;
return true;
}
else
return false;
}
int value;
};
class D1: public virtual B
{
public:
virtual bool supportsProperty(property p)
{
return p == propColour || B::supportsProperty(p);
}
private:
virtual bool do_set_property(property p, int v)
{
if (p == propColour)
{
colour = v;
return true;
}
else
return B::do_set_property(p, v);
}
int colour;
};
class D2: public virtual B
{
public:
virtual bool supportsProperty(property p)
{
return p == propLength || B::supportsProperty(p);
}
private:
virtual bool do_set_property(property p, int v)
{
if (p == propLength)
{
length = v;
return true;
}
else
return B::do_set_property(p, v);
}
int length;
};
class M1: public virtual D1, public virtual D2
{
public:
virtual bool supportsProperty(property p)
{
return D1::supportsProperty(p) || D2::supportsProperty(p);
}
private:
bool do_set_property(property p, int v)
{
return D1::do_set_property(p, v) || D2::do_set_property(p, v);
}
};

Using the strategy pattern if the concrete strategy depends on the concrete parameter type

I'm currently working with a System/Data hierarchy implemented like this:
class SystemData
{
}
class SystemDataA : public SystemData
{
int x;
}
class SystemDataB : public SystemData
{
float y;
}
class System
{
virtual SystemData* getData() = 0;
virtual Result computeData(SystemData*) = 0;
}
class SystemA : public System
{
// really returns SystemDataA
SystemData* getData() override;
Result computeData(SystemData*) override;
}
class SystemB : public System
{
// really returns SystemDataB
SystemData* getData() override;
Result computeData(SystemData*) override;
}
In the end there is a controller class which does sth similar to this:
void foo()
{
for(auto& s : systemVec)
{
SystemData* data = s->getData();
FinalResult final = s->computeData(data);
}
}
Whereas now each specific system dynamic_casts back to the concrete type it is able to process. This seems like pretty bad design and I'd like to refactor this into sth more reasonable. My first idea was to just implement the computation algorithm inside the SystemData classes and then just do:
SystemData* data = s->getData();
FinalResult final = data->compute();
but does it really belong there?
It appears more intuitive to have a separate algorithm hierarchy, probably implemented with the strategy pattern. However then I again have the problem of losing runtime type info of the data because all algorithms get passed the abstract data type and in the end will have to dynamic cast and do nullptr and error checks again. So is it still better to implement the algorithm inside the data classes itself? Can I maybe still implement the hierarchy in a separate module and just add function pointers or a similar construct to the data class? Is there a completely different solution I'm not aware of?

Tightly coupled parallel class hierarchies in C++

For context, I'm working on a C++ artificial-life system involving agents controlled by recurrent neural networks, but the details aren't important.
I'm facing a need to keep two object hierarchies for the "brain" and "body" of my agents separate. I want a variety of different brain and body types that can be coupled to each other at run-time. I need to do this to avoid a combinatorial explosion caused by the multiplicative enumeration of the separate concerns of how a body works and how a brain works.
For example, there are many topologies and styles of recurrent neural network with a variety of different transfer functions and input/output conventions. These details don't depend on how the body of the agent works, however, as long as sensory inputs can be encoded into neural activity and then decoded into actions.
Here is a simple class hierarchy that illustrates the problem and one potential solution:
// Classes we are going to declare
class Image2D; // fake
class Angle2D; // fake
class Brain;
class Body;
class BodyWithEyes;
class BrainWithVisualCortex;
// Brain and Body base classes know about their parallels
class Brain
{
public:
Body* base_body;
Body* body() { return base_body; }
virtual Brain* copy() { return 0; } // fake
// ...etc
};
class Body
{
public:
Brain* base_brain;
Brain* brain() { return base_brain; }
virtual Body* reproduce() { return 0; } // fake
// ...etc
};
// Now introduce two strongly coupled derived classes, with overloaded access
// methods to each-other that return the parallel derived type
class BrainWithVisualCortex : public Brain
{
public:
BodyWithEyes* body();
virtual void look_for_snakes();
virtual Angle2D* where_to_look_next() { return 0; } // fake
};
class BodyWithEyes : public Body
{
public:
BrainWithVisualCortex* brain();
virtual void swivel_eyeballs();
virtual Image2D* get_image() { return 0; } // fake
};
// Member functions of these derived classes
void BrainWithVisualCortex::look_for_snakes()
{
Image2D* image = body()->get_image();
// ... find snakes and respond
}
void BodyWithEyes::swivel_eyeballs()
{
Angle2D* next = brain()->where_to_look_next();
// ... move muscles to achieve the brain's desired gaze
}
// Sugar to allow derived parallel classes to refer to each-other
BodyWithEyes* BrainWithVisualCortex::body()
{ return dynamic_cast<BodyWithEyes*>(base_body); }
BrainWithVisualCortex* BodyWithEyes::brain()
{ return dynamic_cast<BrainWithVisualCortex*>(base_brain); }
// pretty vacuous test
int main()
{
BodyWithEyes* body = new BodyWithEyes;
BrainWithVisualCortex* brain = new BrainWithVisualCortex;
body->base_brain = brain;
brain->base_body = body;
brain->look_for_snakes();
body->swivel_eyeballs();
}
The trouble with this approach is that it's clunky and not particularly type-safe. It does have the benefit that the body() and brain() member functions provide a bit of sugar for derived classes to refer to their partners.
Does anyone know of a better way of accomplishing this tight coupling between 'parallel' hierarchies of classes? Does this pattern come up often enough to have warranted a well-known general solution? A perusal of the usual sources didn't reveal any established patterns that match this problem.
Any help appreciated!
I think what you are doing is approximately correct. You would want the members such as reproduce to be pure virtual, though, so the base classes cannot be created. What is your issue with type-safety? You don't want the Brain subclass and the Body subclass to depend on each others' types.

calling a function from a set of overloads depending on the dynamic type of an object

I feel like the answer to this question is really simple, but I really am having trouble finding it. So here goes:
Suppose you have the following classes:
class Base;
class Child : public Base;
class Displayer
{
public:
Displayer(Base* element);
Displayer(Child* element);
}
Additionally, I have a Base* object which might point to either an instance of the class Base or an instance of the class Child.
Now I want to create a Displayer based on the element pointed to by object, however, I want to pick the right version of the constructor. As I currently have it, this would accomplish just that (I am being a bit fuzzy with my C++ here, but I think this the clearest way)
object->createDisplayer();
virtual void Base::createDisplayer()
{
new Displayer(this);
}
virtual void Child::createDisplayer()
{
new Displayer(this);
}
This works, however, there is a problem with this:
Base and Child are part of the application system, while Displayer is part of the GUI system. I want to build the GUI system independently of the Application system, so that it is easy to replace the GUI. This means that Base and Child should not know about Displayer. However, I do not know how I can achieve this without letting the Application classes know about the GUI.
Am I missing something very obvious or am I trying something that is not possible?
Edit: I missed a part of the problem in my original question. This is all happening quite deep in the GUI code, providing functionality that is unique to this one GUI. This means that I want the Base and Child classes not to know about the call at all - not just hide from them to what the call is
It seems a classic scenario for double dispatch. The only way to avoid the double dispatch is switching over types (if( typeid(*object) == typeid(base) ) ...) which you should avoid.
What you can do is to make the callback mechanism generic, so that the application doesn't have to know of the GUI:
class app_callback {
public:
// sprinkle const where appropriate...
virtual void call(base&) = 0;
virtual void call(derived&) = 0;
};
class Base {
public:
virtual void call_me_back(app_callback& cb) {cb.call(*this);}
};
class Child : public Base {
public:
virtual void call_me_back(app_callback& cb) {cb.call(*this);}
};
You could then use this machinery like this:
class display_callback : public app_callback {
public:
// sprinkle const where appropriate...
virtual void call(base& obj) { displayer = new Displayer(obj); }
virtual void call(derived& obj) { displayer = new Displayer(obj); }
Displayer* displayer;
};
Displayer* create_displayer(Base& obj)
{
display_callback dcb;
obj.call_me_back(dcb);
return dcb.displayer;
}
You will have to have one app_callback::call() function for each class in the hierarchy and you will have to add one to each callback every time you add a class to the hierarchy.
Since in your case calling with just a base& is possible, too, the compiler won't throw an error when you forget to overload one of these functions in a callback class. It will simply call the one taking a base&. That's bad.
If you want, you could move the identical code of call_me_back() for each class into a privately inherited class template using the CRTP. But if you just have half a dozen classes it doesn't really add all that much clarity and it requires readers to understand the CRTP.
Have the application set a factory interface on the system code. Here's a hacked up way to do this. Obviously, apply this changes to your own preferences and coding standards. In some places, I'm inlining the functions in the class declaration - only for brevity.
// PLATFORM CODE
// platformcode.h - BEGIN
class IDisplayer;
class IDisplayFactory
{
virtual IDisplayer* CreateDisplayer(Base* pBase) = 0;
virtual IDisplayer* CreateDisplayer(Child* pBase) = 0;
};
namespace SystemDisplayerFactory
{
static IDisplayFactory* s_pFactory;
SetFactory(IDisplayFactory* pFactory)
{
s_pFactory = pFactory;
}
IDisplayFactory* GetFactory()
{
return s_pFactory;
}
};
// platformcode.h - end
// Base.cpp and Child.cpp implement the "CreateDisplayer" methods as follows
void Base::CreateDisplayer()
{
IDisplayer* pDisplayer = SystemDisplayerFactory::GetFactory()->CreateDisplayer(this);
}
void Child::CreateDisplayer()
{
IDisplayer* pDisplayer = SystemDisplayerFactory::GetFactory()->CreateDisplayer(this);
}
// In your application code, do this:
#include "platformcode.h"
class CDiplayerFactory : public IDisplayerFactory
{
IDisplayer* CreateDisplayer(Base* pBase)
{
return new Displayer(pBase);
}
IDisplayer* CreateDisplayer(Child* pChild)
{
return new Displayer(pChild);
}
}
Then somewhere early in app initialization (main or WinMain), say the following:
CDisplayerFactory* pFactory = new CDisplayerFactory();
SystemDisplayFactory::SetFactory(pFactory);
This will keep your platform code from having to know the messy details of what a "displayer" is, and you can implement mock versions of IDisplayer later to test Base and Child independently of the rendering system.
Also, IDisplayer (methods not shown) becomes an interface declaration exposed by the platform code. Your implementation of "Displayer" is a class (in your app code) that inherits from IDisplayer.

Adding virtual functions without modifying the original classes

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:
class DrawVisitor
{
public:
void draw(const Shape &shape); // dispatches to correct private method
private:
void visitSquare(const Square &square);
void visitCircle(const Circle &circle);
};
Then instead of this:
Shape &shape = getShape(); // returns some Shape subclass
shape.draw(); // virtual method
You would do:
DrawVisitor dv;
Shape &shape = getShape();
dv.draw(shape);
Normally in a Visitor pattern you would implement the draw method like this:
DrawVisitor::draw(const Shape &shape)
{
shape.accept(*this);
}
But that only works if the Shape hierarchy was designed to be visited: each subclass implements the virtual method accept by calling the appropriate visitXxxx 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 to Shape (and all subclasses), you need some other way to dispatch to the correct draw method. One naieve approach is this:
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);
}
// etc.
}
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:
enum ShapeId { SQUARE, CIRCLE, ... };
and there was a virtual method ShapeId Shape::getId() const = 0; that each subclass would override to return its ShapeId. Then you could do your dispatch using a massive switch statement instead of the if-elsif-elsif of dynamic_casts. Or perhaps instead of a switch 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 of type_info pointers. You can build this hashtable 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);
}
}
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:
class ShapeVisitor
{
public:
void visit(const Shape &shape); // not virtual
private:
virtual void visitSquare(const Square &square) = 0;
virtual void visitCircle(const Circle &circle) = 0;
};
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.
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:
#include <iostream>
using namespace std;
// This bit's a bit like your library.
struct Square{};
struct Circle{};
struct AShape{};
// and this is your extra stuff.
template < class T >
class Drawable { public: void draw() const { cout << "General Shape" << endl; } };
template <> void Drawable< Square >::draw() const { cout << "Square!" << endl; };
template <> void Drawable< Circle >::draw() const { cout << "Circle!" << endl; };
template < class T >
void drawIt( const T& obj )
{
obj.draw();
}
int main( int argc, char* argv[] )
{
Drawable<Square> a;
Drawable<Circle> b;
Drawable<AShape> c;
a.draw(); // prints "Square!"
b.draw(); // prints "Circle!"
c.draw(); // prints "General Shape" as there's no specific specialisation for an Drawable< AShape >
drawIt(a); // prints "Square!"
drawIt(b); // prints "Circle!"
drawIt(c); // prints "General Shape" as there's no specific specialisation for an Drawable< AShape >
}
The drawIt() method is probably the key thing here as it represents generic behaviour for any class meeting the requirement of having a draw() 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.