Call templated function with derived class arguments using base class pointers - c++

I have different geometries, which all derived from a base class in order to collect them in a vector. Now I would like to detect collisions between two geometries in this vector. The intersect function is templated with the two geometry types (polymorphism works only with one object as far as I know).
How is it possible to call intersect() correctly? Is there a way without dynamic_cast and checking for != nullptr? Save the enum as constexpr inside the geometry class and use static_cast?
Thank you very much.
enum class GeometryType
{
BOX,
SPHERE,
CAPSULE,
CONE,
CYLINDER,
HALFSPACE
};
class GeometryBase
{
public:
GeometryBase() {}
virtual ~GeometryBase() {}
};
template<enum GeometryType GeomType>
class Geometry : public GeometryBase
{
public:
Geometry() {}
virtual ~Geometry() {}
};
template<enum GeometryType GeomType1, enum GeometryType GeomType2>
void intersect(Geometry<GeomType1>* geom1, Geometry<GeomType2>* geom2)
{
// math stuff
}
void detectCollisions(GeometryBase* geomBase1, GeometryBase* geomBase2)
{
// what can I do here to call the correct intersect<...,...>(...,...)?
}
EDIT: The intersect function is provided by the FCL library, so I cannot change it...

The guideline
Polymorphism should generally be preferred over switch statements which check for a type, because the resulting code is much more type-safe and you get compile-time errors instead of runtime-errors which is generally a good thing. You have the interesting case of a function which takes two objects and which should be dispatched depending dynamically on both argument types.
This is how it's done
Here's one way how to do that: First you need to forward declare all derived classes and write the base class in the following way:
class Box;
class Sphere;
class Cone;
// ...
class GeometryBase
{
public:
virtual bool collidesWith( const GeometryBase & other ) const = 0;
protected:
virtual bool dispatchCollidesWith( const Box & other ) const = 0;
virtual bool dispatchCollidesWith( const Sphere & other ) const = 0;
virtual bool dispatchCollidesWith( const Cone & other ) const = 0;
// ...
};
The function collidesWith() must be implemented to call the dispatchCollidesWith() on other with *this as the argument. Note that *this has different types in the derived classes and hence the different overloads are called. In order to omit too much typing we use a template which does the implementation for us:
template <typename T>
class GeometryImpl : public GeometryBase
{
public:
virtual bool collidesWith( const GeometryBase & other ) const
{
assert( typeid(*this) == typeid(T) );
return other.dispatchCollidesWith( static_cast<const T&>(*this) );
}
};
Now the derived classes can be implemented in the following way:
class Box : public GeometryImpl<Box>
{
protected:
virtual bool dispatchCollidesWith( const Box & other ) const { /* do the math */ }
virtual bool dispatchCollidesWith( const Sphere & other ) const { /* do the math */ }
virtual bool dispatchCollidesWith( const Cone & other ) const { /* do the math */ }
// ...
private:
// data ...
};
Given two geometries geom1 and geom2 you can now test for collision with
geom1.collidesWith( geom2 );
And everything is perfectly type-safe.
A more extensible pattern
There's a backside to this approach: You have to add tons of functions to your base class and it will get crowded easily. Here's how you can make your base class extensible for virtual dispatch, so you don't need to add a virtual function to it everytime you need new functionality:
class GeometryDispatcher;
class GeometryBase
{
public:
void run( GeometryDispatcher & dispatcher ) const = 0;
};
class GeometryDispatcher
{
public:
virtual void dispatch( const Box & shape ) = 0;
virtual void dispatch( const Sphere & shape ) = 0;
virtual void dispatch( const Cone & shape ) = 0;
};
By deriving from GeometryDispatcher you can add a new functionality to your class hierarchy. The run() function must be implemented by the derived classes of GeometryBase in the following way:
void Box::run( GeometryDispatcher & dispatcher ) const
{
dispatcher.dispatch( *this );
}
(This is also known as the first half of the visitor pattern. Read about it, so you can understand my code!) Now you could add a function collidesWithBox() in the following way
class CollidesWithBoxDispatcher : public GeometryDispatcher
{
public:
CollidesWithBoxDispatcher( const Box & box ) : box(box) {}
bool getResult() const { return result; }
virtual void dispatch( const Box & shape ) { ... }
virtual void dispatch( const Sphere & shape ) { ... }
virtual void dispatch( const Cone & shape ) { ... }
private:
bool result;
const Box & box;
};
bool collidesWithBox( const GeometryBase & shape, const Box & box )
{
CollidesWithBoxDispatcher d( box );
shape.run( d );
return d.result;
}
You can implement the functions collidesWithSphere() and collidesWithCone() analogously. Finally, you can implement the function collidesWith() this way:
class CollidesWithDispatcher : public GeometryDispatcher
{
public:
CollidesWithDispatcher( const GeometryBase & shape ) : shape(shape) {}
bool getResult() const { return result; }
virtual void dispatch( const Box & box )
{
result = collidesWithBox( shape, box );
}
virtual void dispatch( const Sphere & sphere ) { ... }
virtual void dispatch( const Cone & cone ) { ... }
private:
bool result;
const GeometryBase & shape;
};
bool collidesWith( const GeometryBase & shape1, const GeometryBase shape2 )
{
CollidesWithDispatcher d( shape2 );
shape1.run( d );
return d.result;
}
A lot of code to write but you get a double dispatch this way by facilitating the visitor pattern. Happy end. :)

In intersect, I'm guessing that:
// math stuff
is doing three things:
Get some values from geom1
Get some values from geom2
Do some math using the above values and process the result
If that's the case, here's how I'd do this.
First, make intersect a non-template function that takes two parameters, both of type GeometryBase*.
Add pure virtual methods to GeometryBase which defines an interface to return the "values" needed in steps 1 & 2 above. You may need to give a bit of a think to how best to represent these values in a sufficiently generic way so that all subclasses can return the same type of things.
Implement the pure virtaul in each of the GeometryBase-derived concrete classes.
Implement intersect in terms of calling these virtual methods (via the GeometryBase pointer; no need to cast in any way or apply the visitor pattern).
You could make intersect a free function (in a namespace, please!), or possibly implement it in a class. It might (or might not) to make this a member function of GeometryBase, in which case this would be used in leiu of one of the GeometryBase* parameters.

You should better use inheritance instead of using an enum. Then you could create a generic intersect function that takes GeometryBase objects as arguments: it will be generic for GeometryBase children.
It means that you must provide the needed interface in GeometryBase in order to compute the intersection:
class GeometryBase
{
//...
public: // your interface
virtual Vertices getVertices() const; // can be virtual, or not
//...
}
void intersect(GeometryBase* geom1, GeometryBase* geom2)
{
// math stuff, calling geom1->getVertices() & ...
}
//specializations
class Box: public GeometryBase
{
public:
virtual Vertices getVertices() const; // implement what you need to specialize
}
class Cone : public GeometryBase
{
}
// etc...
Then you vector should look like:
std::vector<GeometryBase*> geometries;

The way I would approach this would be manual double dispatch with help from a type mapping.
Here is a really simple version:
class GeometryBase
{
public:
GeometryBase() {}
virtual GeometryBase() {}
virtual void doIntersect( GeometryBase* other ) = 0;
virtual GeometryType GetGeometryType() const = 0;
};
// forward decl:
template<enum GeometryType GeomType1, enum GeometryType GeomType2>
void intersect(Geometry<GeomType1>* geom1, Geometry<GeomType2>* geom2);
template<enum GeometryType GeomType>
class Geometry : public GeometryBase
{
public:
Geometry() {}
virtual Geometry() {}
GeometryType GetGeometryType() const { return GeomType; }
virtual void doIntersect( GeometryBase* other ) {
switch (other->GetGeometryType()) {
case GeometryType::BOX:
intersect( this, static_cast<GeometryType<GeometryType::BOX>*>(other) );
break;
// etc
}
}
};
where we do manual dynamic double dispatch in a switch statement.
We can build some infrastructure to make this easier in a number of ways. You can write a fast_cast that supports casting your base class into a number of subclasses using only a virtual function lookup and call (which is faster than a dynamic_cast typically). You can write a function that replaces the copy/paste case expressions above with a magic switch that does it (but the boilerplate to do that is longer than the above code).
You could write a macro to write out the cases (thereby obeying DRY, and reducing some categories of errors).
But the basic problem is one of double dispatch, and double dispatch requires manual work on the part of the programmer in C++.

Related

Dynamic ad hoc polymorphism in C++

In my C++ code, I have a collection of classes A1, A2, ..., all derived from a class A. I also have a vector v<*A> holding pointers to objects all of type A. I want to implement a function foo(A *x, A *y) that is dynamically ad hoc polymorphic in the type of x and y. To make this more concrete, imagine A is Shape, A1, A2, ..., are Circle, Rect, ..., and foo is intersects(Shape *x, Shape *y).
I could overload foo with declarations like foo(A1 *x, A2 *y) for the combinations of derived types of A that I care about, however this will not work for the objects referenced by my vector v since function overloading, unlike virtual methods, is handled statically. I also cannot use virtual methods of the form A1::foo(A2 *y) since this only dynamically resolves the type of the method's class (A1) and not the type of the argument (A2).
The only solution I've thought of is to implement foo as follows:
void foo(A *x, A*y) {
if (A1* a1 = dynamic_cast<A1*>(x)) {
if (A1* a1 = dynamic_cast<A1*>(y)) {
...
}
...
}
if (A2* a2 = dynamic_cast<A2*>(x)) {
if (A1* a1 = dynamic_cast<A1*>(y)) {
...
}
...
}
...
}
However, I've always been told that resorting to dynamic casts is rarely a good idea. Is there a more idiomatic way to achieve this?
This is double dispatch. The visitor pattern can accomplish this. You need a virtual function which makes the first type concrete to apply a visitor. And then you need another virtual function to make the second type concrete and return a visitor:
struct Shape
{
// Each derived class simply calls visit with the concrete type:
// return visitor.visit(*this);
virtual bool accept(const IntersectionVisitor& visitor) const = 0;
// Each derived class return a visitor which knows how to calculate
// the intersection of this particular class type with all types of
// shapes. The visit() overrides of this visitor have access to both
// concrete shape types.
virtual IntersectionVisitor intersection_visitor() const = 0;
};
struct IntersectionVisitor
{
// Calculate the intersection of this concrete shape with a Circle
virtual bool visit(const Circle&) = 0;
// Calculate the intersection of this concrete shape with a Rect
virtual bool visit(const Rect&) = 0;
};
bool intersects(const Shape& shape1, const Shape& shape2)
{
return shape2.accept(shape1.intersection_visitor());
}
Just because you can doesn't mean you should. You can do this more simply with variants:
using Shape = std::variant<Circle, Rect, ...>;
bool intersects(const Circle&, const Circle&) { ... }
bool intersects(const Circle&, const Rect&) { ... }
// all shape combinations, like before
// Visitation is just std::visit:
bool intersects(const Shape& shape1, const Shape& shape2)
{
return std::visit([](const auto& s1, const auto& s2) {
return intersects(s1, s2);
}, shape1, shape2);
}

Passing object of base class to function of reference to derived class

I'm trying to write code which can find the distance between lots of different types of shapes. I've defined a base class Shape with a virtual distance(Shape& otherShape) function to find the distance to another shape and then want to define that for all my derived classes.
The problem is that there are lots of possible pairs of shapes, so my solution was to define a set of distance functions outside the classes (circle-circle, circle-square, square-tri etc.) and then call the corresponding one from the distance function. I've added a mini example of what I mean below, with just one derived class Circle to demonstrate the problem.
When I try and call my specific circleCircleDistance function I get an error because it can't convert the base class into the derived class. Is there any way I can address this or will my design as it stands just not work?
enum ShapeType{CIRCLE, SQUARE};
class Shape {
public:
ShapeType type;
virtual double distance(Shape& otherShape) = 0;
};
class Circle : public Shape {
public:
ShapeType type = CIRCLE;
double distance(Shape& otherShape) override;
};
double circleCircleDistance(Circle& circle1, Circle& cirlce2){
return 0; //pretend this does the calculation
};
double Circle::distance(Shape &otherShape) {
switch (otherShape.type){
case CIRCLE:
//Here I get the error
//cannot bind base class object of type Shape to derived class reference Circle& for 2nd argument
return circleCircleDistance(*this, otherShape);
}
}
You would have to cast the Shape& to a Circle&
return circleCircleDistance(*this, static_cast<Circle&>(otherShape));
As an aside, I'd handle your types a bit differently
class Shape {
public:
virtual ShapeType get_type() const = 0; // derived classes must override this
virtual double distance(Shape& otherShape) = 0;
};
class Circle : public Shape {
public:
ShapeType get_type() const override { return CIRCLE; } // here's your override
double distance(Shape& otherShape) override;
};
...
{
switch (otherShape.get_type()){
Otherwise you're going to get into a situation where type is shadowed from the derived/base classes depending how you access it.
Multiple dispatch is not natively supported in C++.
We only have single dispatch thanks to virtual method.
So you can implement double dispatch for your cases.
An (C++17) "alternative" option is to use std::variant, which has std::visit which implement multiple dispatch:
You can keep inheritance or drop it.
struct Circle {
Point center;
float radius;
};
struct Rectangle {
Point topLeft;
Point bottomRight
};
using Shape = std::variant<Square, Rectangle>;
double distance(const Square&, const Square&);
double distance(const Square&, const Rectangle&);
double distance(const Rectangle&, const Square&);
double distance(const Rectangle&, const Rectangle&);
double distance(const Shape& shape1, const Shape& shape2)
{
return std::visit([](const auto& shape1, const auto& shape2){
return distance(shape1, shape2);
},
shape1,
shape2);
}
In c++20 you could use template specialization with concepts for this kind of problem

C++ Overload an overrided method

Is it possible in C++ to overload in the child classes an overrided method?
I'm asking this because I have many child classes that although they are the same (in my case game objects) they interact in different ways with each others.
So, I need to create a function like void processCollision(GameObject obj) in the superclass.
But that could be overloaded in the child classes depending on the class of the GameObject (if it's a building, a car ...).
I'm just trying to run from the alternative which is using upcasting and RTTI.
What you're trying to implement is normally called "multiple dispatch" and unfortunately C++ doesn't support it directly (because in C++ view methods are bounded with classes and there are no multimethods).
Any C++ solution will require some coding for the implementation.
One simple symmetric way to implement it is to create a map for the supported cases:
typedef void (*Handler)(Obj *a, Obj *b);
typedef std::map<std::pair<OType, OType>, Handler> HandlerMap;
HandlerMap collision_handlers;
then the collision handling is:
HandlerMap::iterator i =
collision_handlers.find(std::make_pair(a->type, b->type));
if (i != collision_handlers.end()) i->second(a, b);
and the code goes in a free function.
If speed is a key factor and the object type can be coded in a small integer (e.g. 0...255) the dispatch could become for example:
collision_handlers[(a->type<<8)+b->type](a, b);
where collision handler is just an array of function pointers, and the speed should be equivalent to a single virtual dispatch.
The wikipedia link at the start of the answer lists another more sophisticated option for C++ (the visitor pattern).
"I'm just trying to run from the alternative which is using upcasting and RTTI."
Virtual polymorphism doesn't need upcasting or RTTI. Usually that's what virtual member functions are for:
class GameObject {
public:
virtual void processCollision(GameObject& obj);
};
class SomeGameObject1 : public GameObject {
public:
// SomeGameObject1's version of processCollision()
virtual void processCollision(GameObject& obj) {
// e.g here we also call the base class implementation
GameObject::processCollision();
// ... and add some additional operations
}
};
class SomeGameObject2 : public GameObject {
public:
// SomeGameObject2's version of processCollision()
virtual void processCollision(GameObject& obj) {
// Here we leave the base class implementation aside and do something
// completely different ...
}
};
MORE ADDITIONS AND THOUGHTS
As you're mentioning upcasting I'd suspect you want to handle collisions differently, depending on the actual GameObject type passed. This indeed would require upcasting (and thus RTTI) like follows
class Building : public GameObject {
public:
virtual void processCollision(GameObject& obj) {
Car* car = dynamic_cast<Car*>(&obj);
Airplane* airplane = dynamic_cast<Airplane*>(&obj);
if(car) {
car->crash();
}
else if(airplane) {
airplane->crash();
collapse();
}
void collapse();
};
Based on the above, that makes me contemplative about some design/architectural principles:
May be it's not the best idea to place the processCollision() implementation strategy to the GameObject classes themselves. These shouldn't know about each other (otherwise it will be tedious to introduce new GameObject types to the model)
You should introduce a kind of GameManager class that keeps track of moving/colliding GameObject instances, and chooses a GameObjectCollisionStrategy class implementing void processCollision(GameObject& a,GameObject& b); based on the actual types of a and b.
For choosing the strategy, and resolve the final GameObject implementations and corresponding strategies, you should concentrate all of that business knowdlege to a CollisionStrategyFactory, and delegate to this.
The latter would look something like this
class GameObjectCollisionStrategy {
public:
virtual processCollision(GameObject& a,GameObject& b) const = 0;
};
class CollideBuildingWithAirplane : public GameObjectCollisionStrategy {
public:
virtual void processCollision(GameObject& a,GameObject& b) const {
Building* building = dynamic_cast<Building*>(a);
Airplane* airplane = dynamic_cast<Airplane*>(b);
if(building && airplane) {
airplane->crash();
building->collapse();
}
}
};
class CollideBuildingWithCar : public GameObjectCollisionStrategy {
public:
virtual void processCollision(GameObject& a,GameObject& b) const {
Building* building = dynamic_cast<Building*>(a);
Car* car = dynamic_cast<Car*>(b);
if(building && car) {
car->crash();
}
}
};
class CollisionStrategyFactory {
public:
static const GameObjectCollisionStrategy& chooseStrategy
(GameObject* a, GameObject* b) {
if(dynamic_cast<Building*>(a)) {
if(dynamic_cast<Airplane*>(b)) {
return buildingAirplaneCollision;
}
else if(dynamic_cast<Car*>(b)) {
return buildingCarCollision;
}
}
return defaultCollisionStrategy;
}
private:
class DefaultCollisionStrategy : public GameObjectCollisionStrategy {
public:
virtual void processCollision(GameObject& a,GameObject& b) const {
// Do nothing.
}
};
// Known strategies
static CollideBuildingWithAirplane buildingAirplaneCollision;
static CollideBuildingWithCar buildingCarCollision;
static DefaultCollisionStrategy defaultCollisionStrategy;
};
class GameManager {
public:
void processFrame(std::vector<GameObject*> gameObjects) {
for(std::vector<GameObject*>::iterator it1 = gameObjects.begin();
it1 != gameObjects.end();
++it1) {
for(std::vector<GameObject*>::iterator it2 = gameObjects.begin();
it2 != gameObjects.end();
++it2) {
if(*it1 == *it2) continue;
if(*it1->collides(*it2)) {
const GameObjectCollisionStrategy& strategy =
CollisionStrategyFactory::chooseStrategy(*it1,*it2);
strategy->processCollision(*(*it1),*(*it2));
}
}
}
}
};
Alternatively you may want to opt for static polymorphism, which also works without RTTI, but needs all types known at compile time. The basic pattern is the so called CRTP.
That should look as follows
class GameObject {
public:
// Put all the common attributes here
const Point& position() const;
const Area& area() const;
void move(const Vector& value);
};
template<class Derived>
class GameObjectBase : public GameObject {
public:
void processCollision(GameObject obj) {
static_cast<Derived*>(this)->processCollisionImpl(obj);
}
};
class SomeGameObject1 : public GameObjectBase<SomeGameObject1 > {
public:
// SomeGameObject1's version of processCollisionImpl()
void processCollisionImpl(GameObject obj) {
}
};
class SomeGameObject2 : public GameObjectBase<SomeGameObject2 > {
public:
// SomeGameObject2's version of processCollisionImpl()
void processCollisionImpl(GameObject obj) {
}
};
But this would unnecessarily complicate the design, and I doubt it will provide any benefits for your use case.

typecasting and check is an instance exists in a vector

I have a virtual class Shape. class Rectangle, Triangle, Circle inherit from Shape and have different characteristics (size, number of side...).
I want to store different shape in a structure (let's say a vector).
so my vector would be: vector<Shape*> myvec;
I would like to know how it is possible to know if a given instance of a shape is present in the vector (ex: new Circle(diameter 10);).
I have heard about dynamic cast but I don't understand at all how to use it?
class Shape
{
public:
Shape(){}
virtual int Size()=0;
virtual int Sides()=0;
virtual bool isequal(const Shape & rhs)=0;
int size,sides;
};
class Circle : public Shape
{
public:
Circle(int diameter):size(diameter)
{
sides=0;
}
bool isequal(const Circle &rhs)
{
return size==rhs.size;
}
int size,sides;
};
class Rectangle: public Shape
{
Rectangle(int nbsides,int size1,int size2 ): sides(nbsides),size1(size1),size2(size2){}
bool isequal(const Rectangle &rhs)
{
return (size1==rhs.size1 && rhs.size2==size2);
}
int sides,size1,size2;
};
dynamic_cast is right:
Shape* shape = myvec[0];
Circle* circle = dynamic_cast<Circle*>(shape);
if(circle != nullptr)
; // it's a Circle! Do something circly.
else
; // it's not a Circle. Do something else.
But a better answer to the question is that, in a perfect world, you should use polymorphism such that it is rarely if ever necessary to do this.
Based on the additional comments below, I think you might want to use a pure virtual isequal() in Shape, with dynamic_casts inside the various implementations (the inside of a polymorphic comparison function is one of the few places I can use dynamic_cast without feeling the need to wash my hands afterwards :) ).
// edited out code that isn't directly relevant
class Shape
{
public:
virtual bool isequal(const Shape& rhs)=0;
};
class Circle : public Shape
{
public:
// snip
virtual bool isequal(const Shape &rhs) override
{
Circle* rhsAsCircle = dynamic_cast<Circle*>(&rhs);
if(rhsAsCircle == nullptr)
return false; // not a Circle; can't be equal
return size==rhsAsCircle->size;
}
};
Then elsewhere:
Circle searchCircle(10);
for(Shape* shape : myvec)
if(shape->isequal(searchCircle))
; // we have a match!

Adding class functionality via composition

Suppose we have an abstract class Element from which classes Triangle and Quadrilateral are derived from.
Suppose yet that these classes are used in conjunction with interpolation methods that depend on the shape of the element. So, basically we create an abstract class InterpolationElement from which we derive InterpolationTriangle and InterpolationQuadrilateral.
Then, to include the interpolation functionality in the Triangle and Quadrilateral classes, we add a const-reference data member in class Element of type InterpolationElement, that is:
class Element
{
public:
Element(const InterpolationElement& interp);
const InterpolationElement& getInterpolation() const;
private:
const InterpolationElement& interpolation;
};
We then create a method (as described by Scott Meyers, Effective C++) that instanciate a local static object of class InterpolationTriangle as
const InterpolationTriangle& getInterpolationTriangle()
{
static InterpolationTriangle interpolationTriangle;
return interpolationTriangle;
}
So that class Triangle can be constructed like:
class Triangle : public Element
{
public:
Triangle() : Element( getInterpolationTriangle() ) {}
};
Here is my question: is this approach correct in order to incorporate interpolation methods on my class Element? Is this used in professional scenarios?
I could implement directly all the interpolation methods on class Element (as pure virtual) and the override them in the derived classes Triangle and Quadrilateral. However, this approach seems to me to be cumbersome, since every time I need to improve or implement new interpolation functionalities I would have to do that on these classes. Moreover, the classes get bigger and bigger (many methods) using this approach.
I would like to hear from you some tips and comments
Thanks in advance.
Additional details:
class InterpolationElement
{
public:
InterpolationElement();
virtual double interpolationMethod1(...) = 0;
:
virtual double interpolationMethodN(...) = 0;
}
class InterpolationTriangle : public InterpolationElement
{
public:
InterpolationTriangle () {}
virtual double interpolationMethod1(...) { // interpolation for triangle }
:
virtual double interpolationMethodN(...) { // interpolation for triangle }
}
class InterpolationQuadrilateral : public InterpolationElement
{
public:
InterpolationTriangle () {}
virtual double interpolationMethod1(...) { // interpolation for quadrilateral}
:
virtual double interpolationMethod1(...) { // interpolation for quadrilateral}
}
The classes are used in conjunction with interpolation methods. Why do those methods need to be in a singleton object? The singleton here looks very problematic.
class Element
{
public:
virtual double interpolationMethod1(...) = 0;
:
virtual double interpolationMethodN(...) = 0;
};
class Triangle : public Element
{
public:
virtual double interpolationMethod1(...) { // interpolation for triangle }
:
virtual double interpolationMethodN(...) { // interpolation for triangle }
}
Also, welcome to SO!
This is reminiscent of a question that I had answered here. The same idea about the separation of data containers and the strategies.
There is one little issue with your proposal: you have added an interpolation related method to your base class and you've changed the constructor...
So first of all, if you wish to do it this way, here is how you should do it:
class Element
{
public:
private:
// similar signature to a `clone` method
virtual InterpolationElement* interpolation() const = 0;
};
class Triangle
{
public:
private:
virtual InterpolationTriangle* interpolation() const
{
return new InterpolationTriangle();
}
};
There are 2 advantages here:
It's no longer necessary to change the constructor of each of the derived objects
The strategy object is no longer const, which allows it to maintain state during the computation... like a reference to the current object being interpolated.
However, this still requires to change the Element class, and each of its derived classes. Doesn't it bother you ;) ?
Well, it's time (for once) to call upon a Design Pattern: Visitor.
It's a little different from the strategy idea, relying on double dispatch to work properly. However it allows you to tweak the hierarchy of Elements ONCE (with an accept method) and then to add as many operations as you wish. And that is great.
You can always mess a little bit with templates.
First we have a top class.
class Element {
public:
virtual void calculate() const = 0;
};
... but then we also have a class in the middle of the hierarchy which is actually a template. Template can't be the top level class, as templates with different parameters are different classes. The idea is that we give an interpolation class as a type parameter to the element.
template <typename Interpolation>
class Element_Impl : public Element {
protected:
Interpolation m_interpolation;
};
And interpolation classes. Notice, they aren't siblings, because they don't need to.
class InterpolationTriangle {
public:
double interpolate(double a, double b) const {
std::cout << "interpolation triangle" << std::endl;
}
};
class InterpolationQuadrilateral {
public:
double interpolate(double a, double b) const {
std::cout << "interpolation quadrilateral" << std::endl;
}
};
And finally the real elements and the small main procedure.
class Triangle : public Element_Impl<InterpolationTriangle> {
public:
void calculate() const {
m_interpolation.interpolate(1.0, 2.0);
}
};
class Quadrilateral : public Element_Impl<InterpolationQuadrilateral> {
public:
void calculate() const {
m_interpolation.interpolate(2.0, 3.0);
}
};
int main() {
const Element &a = Triangle();
const Element &b = Quadrilateral();
a.calculate();
b.calculate();
}
Summary:
you can easily switch interpolation class for each element if needed.
there aren't double vtable access (first for Element's calculate and then for InterpolationElement's intepolate methods) as in the Matthieu's example. Each element knows at compile time which interpolation class it is using.
Element_Impl is an ugly bit, but it saves us from copypasta. You can expand it even further by implementing interpolation method wrappers
http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern
One way is to use static methods, and defining a wrapper in Element_Impl - still only in one place.
class Element {
public:
virtual void calculate() const = 0;
};
template <typename Interpolation>
class Element_Impl : public Element {
protected:
void interpolate(double, double) const {
Interpolation::interpolate(1, 1);
}
};
class InterpolationTriangle {
public:
static double interpolate(double a, double b) {
std::cout << "interpolation triangle" << std::endl;
}
};
class InterpolationQuadrilateral {
public:
static double interpolate(double a, double b) {
std::cout << "interpolation quadrilateral" << std::endl;
}
};
class Triangle : public Element_Impl<InterpolationTriangle> {
public:
void calculate() const {
interpolate(1.0, 2.0);
}
};
class Quadrilateral : public Element_Impl<InterpolationQuadrilateral> {
public:
void calculate() const {
interpolate(2.0, 3.0);
}
};
int main() {
const Element &a = Triangle();
const Element &b = Quadrilateral();
a.calculate();
b.calculate();
}
What first comes to my mind is the GoF Design Pattern Visitor
From what I understand of your problem, this pattern is conceived to exactly solve this issue.
Each Visitor object defines an interpolation technique, or an algorithm to apply to your object.
Thus the Element class doesn't grow at all with each new functionnality. Once in place, the Visitor pattern enables to enrich functionnality without touching to the Base class definition.