Most Elegant Way to Get Around This Polymorphism Issue - c++

EDIT: I'm working with C++.
So, I am creating methods/functions to test intersection between shapes. I essentially have this:
class Shape {};
class Rectangle : public Shape {};
class Circle : public Shape {};
class Line : public Shape {};
Now, I need to decide on the best way to write the actual methods/functions to test intersection. But all my shapes will be stored in a list of Shape pointers, so I will be calling a method/function of the basic form:
bool intersects (Shape* a, Shape* b);
At that point, I need to determine which types of shapes 'a' and 'b' are, so I can properly detect collisions. I can easily do one of them, by just using some virtual methods:
class Shape
{
virtual bool intersects (Shape* b) = 0;
}
That would determine one of the shapes ('a' is now 'this'). However, I would still need to get the type of 'b'. The obvious solution is to give Shape an 'id' variable to classify which shape it is, and then 'switch' through those, and then use dynamic_cast. However, that is not very elegant, and it feels like there should be a more OO way to do this.
Any suggestions?

As #Mandarse pointed out, this is typical double dispatch issue. In Object Oriented languages, or like C++ languages that can implement Object Oriented concepts, this is usually solved using the Visitor Pattern.
The Visitor interface itself defines one callback per concrete type, in general.
class Circle;
class Rectangle;
class Square;
class Visitor {
public:
virtual void visit(Circle const& c) = 0;
virtual void visit(Rectangle const& r) = 0;
virtual void visit(Square const& s) = 0;
};
Then, the Shape hierarchy is adapted for this. We need two methods: one to accept any type of visitor, the other to create the "appropriate" intersection visitor.
class Visitor;
class Intersecter;
class Shape {
public:
virtual void accept(Visitor&) const = 0; // generic
virtual Intersecter* intersecter() const = 0;
};
The intersecter is simple:
#include "project/Visitor.hpp"
class Intersecter: public Visitor {
public:
Intersecter(): result(false) {}
bool result;
};
For example, for Circle it will give:
#include "project/Intersecter.hpp"
#include "project/Shape.hpp"
class Circle;
class CircleIntersecter: public Intersecter {
public:
explicit CircleIntersecter(Circle const& c): _left(c) {}
virtual void visit(Circle const& c); // left is Circle, right is Circle
virtual void visit(Rectangle const& r); // left is Circle, right is Rectangle
virtual void visit(Square const& s); // left is Circle, right is Square
private:
Circle const& _left;
}; // class CircleIntersecter
class Circle: public Shape {
public:
virtual void accept(Visitor& v) const { v.visit(*this); }
virtual CircleIntersecter* intersecter() const {
return new CircleIntersecter(*this);
}
};
And the usage:
#include "project/Intersecter.hpp"
#include "project/Shape.hpp"
bool intersects(Shape const& left, Shape const& right) {
boost::scope_ptr<Intersecter> intersecter(left.intersecter());
right.accept(*intersecter);
return intersecter->result;
};
If other methods need a double-dispatch mechanism, then all you need to do is create another "Intersecter-like" class that wrap the result and inherits from Visitor and a new "Factory" method rooted in Shape that is overriden by derived classes to provide the appropriate operation. It is a bit long-winded, but does work.
Note: it is reasonable to except intersect(circle, rectangle) and intersect(rectangle, circle) to yield the same result. You can factor the code is some methods and have CircleIntersecter::visit delegates to the concrete implementation. This avoid code duplication.

Andrei Alexandrescu detailed this problem in his classic Modern C++ Design. The companion library Loki contains the the implementation for Multi-Methods.
Update
Loki provides three implementations of Multi-Methods, depending on the user's needs. Some are for simplicity, some are for speed, some are good for low coupling and some provide more safety than others. The chapter in the book spans nearly 40 pages, and it assumes the reader is familiar with many of the book's concepts -- if you are comfortable using boost, then Loki may be down your alley. I really can't distill that to an answer acceptable for SO, but I've pointed you to the best explanation of the subject for C++ that I know of.

C++ run-time polymorphism has a single dispatch (the base class vtable).
There are various solution to your problem but none of them is "elegant", since they all try to force the language to do more that it can natively support (Alexandrescu Loki multimethods is a very goodly hidden set of hacks: it encapsulates the "bad things", but doesn't make then good)
The concept, here, it that you need to write all the N2 functions of the possible combinations and find a way to call them based on the actual runtime-type of TWO parameters.
The "visitor pattern" (call back a virtual unction from another virtual function), the "mutimethod" technic (use a generic dspatch table), the "dynamic cast" into a virtual function or the "dual dynamic_cast" out all of the functions all do the same thing: call a function after two indirection. None of them can technically be defined "better then the other" since the resulting performance is mostly the same.
But some of them cost more then the other in code writing and other cost more in code maintenance.
You have most likely to try to estimate in your case what the trade-off is. How many other classes do you think you may need to add in the future?

You can add a field shapeType to each Shape
For example:
class Shape {
virtual shapetype_t getShapeType() const;
// ...
}

I've played with the shapes intersection resolving dispatch approach just for fun. I didn't like the idea of extending classes each time new shape appear. I thought of the collection of intersection resolvers which is iterated to find out if there is one that supports given pair of shapes. If new shape appear new intersection resolvers are to be added to the collection.
I don't think that it is a most optimal approach in terms of performance, since the resolvers iterated through and dynamic casts executed until proper resolver is found.
But, nevertheless...
Intersection resolver takes two shapes and return resolving result which contain supported and intersect flags.
struct Intersection_resolution {
bool supported;
bool intersect;
};
class IIntersection_resolver {
public:
virtual Intersection_resolution intersect(Shape& shape1, Shape& shape2) = 0;
};
Resolver implementation. Template class, takes two shapes, checks if it supports them and if so invokes check_intersection method. Latter should be defined in specification. Note that the the pair should be specified only ones, i.e. if Rectangle-Circle specified, no need to specify Circle-Rectangle.
template<typename S1, typename S2>
class Intersection_resolver : public IIntersection_resolver {
private:
bool check_intersection(S1& s1, S2& s2);
public:
Intersection_resolution intersect(Shape& shape1, Shape& shape2) override final {
S1* s1 = dynamic_cast<S1*>(&shape1);
S2* s2{nullptr};
if (s1)
s2 = dynamic_cast<S2*>(&shape2);
else {
s1 = dynamic_cast<S1*>(&shape2);
if (s1)
s2 = dynamic_cast<S2*>(&shape1);
}
bool supported{false};
bool intersect{false};
if (s1 && s2) {
supported = true;
intersect = check_intersection(*s1, *s2);
}
return Intersection_resolution{supported, intersect};
}
};
Couple of specifications...
template<>
bool Intersection_resolver<Rectangle, Rectangle>::check_intersection(Rectangle& r1, Rectangle& r2) {
cout << "rectangles intersect" << endl;
return true;
}
template<>
bool Intersection_resolver<Rectangle, Circle>::check_intersection(Rectangle& r1, Circle& r2) {
cout << "rectangle intersect circle" << endl;
return true;
}
Resolvers collection.
class Intersection_resolvers {
std::vector<IIntersection_resolver*> resolvers_;
public:
Intersection_resolvers(std::vector<IIntersection_resolver*> resolvers) :resolvers_{resolvers} {}
Intersection_resolution intersect(Shape& s1, Shape& s2) {
Intersection_resolution intersection_resolution;
for (IIntersection_resolver* resolver : resolvers_) {
intersection_resolution = resolver->intersect(s1, s2);
if (intersection_resolution.supported)
break;
}
return intersection_resolution;
}
};
Intersection_resolver<Rectangle, Rectangle> rri;
Intersection_resolver<Rectangle, Circle> rci;
Intersection_resolvers intersection_resolvers{{&rri, &rci}};
Usage.
int main() {
Rectangle r;
Triangle t;
Circle c;
Shape* shapes[]{&r, &t, &c};
for (auto shape : shapes) {
shape->draw();
}
for (auto shape : shapes) {
for (auto other : shapes) {
auto intersection_resolution = intersection_resolvers.intersect(*shape, *other);
if (!intersection_resolution.supported) {
cout << typeid(*shape).name() << " - " << typeid(*other).name() << " intersection resolving not supported" << endl;
}
}
}
}
Output.
rectangle drawn
triangle drawn
circle drawn
rectangles intersect
9Rectangle - 8Triangle intersection resolving not supported
rectangle intersect circle
8Triangle - 9Rectangle intersection resolving not supported
8Triangle - 8Triangle intersection resolving not supported
8Triangle - 6Circle intersection resolving not supported
rectangle intersect circle
6Circle - 8Triangle intersection resolving not supported
6Circle - 6Circle intersection resolving not supported

Related

Overload a function with a derived class argument if you only have a pointer to the base class in C++

I have seen people using containers of pointers to the base class to hold groups of objects which share the same virtual functions. Is it possible to use overloaded functions of the derived class with these base class pointers. It is hard to explain what I mean but (I think) easy to show with code
class PhysicsObject // A pure virtual class
{
// Members of physics object
// ...
};
class Circle : public PhysicsObject
{
// Members of circle
// ...
};
class Box : public PhysicsObject
{
// Members of box
// ...
};
// Overloaded functions (Defined elsewhere)
void ResolveCollision(Circle& a, Box& b);
void ResolveCollision(Circle& a, Circle& b);
void ResolveCollision(Box& a, Box& b);
int main()
{
// Container to hold all our objects
std::vector<PhysicsObject*> objects;
// Create some circles and boxes and add to objects container
// ...
// Resolve any collisions between colliding objects
for (auto& objA : objects)
for (auto& objB : objects)
if (objA != objB)
ResolveCollision(*objA, *objB); // !!! Error !!! Can't resolve overloaded function
}
My first idea was to make these functions be virtual class members also (shown below) but I quickly realised that it has exactly the same issue.
class Circle;
class Box;
class PhysicsObject // A pure virtual class
{
virtual void ResolveCollision(Circle& a) = 0;
virtual void ResolveCollision(Box& a) = 0;
// Members of physics object
// ...
};
class Box;
class Circle : public PhysicsObject
{
void ResolveCollision(Circle& a);
void ResolveCollision(Box& a);
// Members of circle
// ...
};
class Circle;
class Box : public PhysicsObject
{
void ResolveCollision(Circle& a);
void ResolveCollision(Box& a);
// Members of box
// ...
};
From googling the problem it seems like possibly it can be solved using casting but I can't figure out how to find the correct type to cast to (also it is ugly). I suspect I am asking the wrong question and there is a better way to structure my code which sidesteps this problem and achieves the same result.
With double dispatch, it would be something like:
class Circle;
class Box;
// Overloaded functions (Defined elsewhere)
void ResolveCollision(Circle& a, Box& b);
void ResolveCollision(Circle& a, Circle& b);
void ResolveCollision(Box& a, Box& b);
class PhysicsObject // A pure virtual class
{
public:
virtual ~PhysicsObject() = default;
virtual void ResolveCollision(PhysicsObject&) = 0;
virtual void ResolveBoxCollision(Box&) = 0;
virtual void ResolveCircleCollision(Circle&) = 0;
};
class Circle : public PhysicsObject
{
public:
void ResolveCollision(PhysicsObject& other) override { return other.ResolveCircleCollision(*this); }
void ResolveBoxCollision(Box& box) override { ::ResolveCollision(*this, box);}
void ResolveCircleCollision(Circle& circle) override { ::ResolveCollision(*this, circle);}
// ...
};
class Box : public PhysicsObject
{
public:
void ResolveCollision(PhysicsObject& other) override { return other.ResolveBoxCollision(*this); }
void ResolveBoxCollision(Box& box) override { ::ResolveCollision(box, *this);}
void ResolveCircleCollision(Circle& circle) override { ::ResolveCollision(circle, *this);}
// ...
};
The way I'd do this is to build a Extent class that tells you about the physical perimeter of an object, perhaps with respect to its barycentre. Additionally, you'd have
virtual const Extent& getExtent() const = 0;
in the PhysicsObject class. You then implement getExtent once per object type.
Your collision detection line becomes
ResolveCollision(objA->getExtent(), objB->getExtent());
Although, in a sense, this does little more than kick the can down the road as the complexity is pushed to the Extent class, the approach will scale well since you only need to build one method per object.
The alternative double dispatch mechanism is intrusive insofar that a new shape requires adjustment to all existing shapes. Having to recompile the Circle class, for example, if you introduce an Ellipse class, say, is a code smell to me.
I am going to sketch an implementation that does not rely on double-dispatch. Instead, it makes use of a table where all functions are registered. This table is then accessed using the dynamic type of the objects (passed as base class).
First, we have some example shapes. Their types are enlisted inside an enum class. Every shape class defines a MY_TYPE as their respective enum entry. Furthermore, they have to implement the base class' pure virtual type method:
enum class ObjectType
{
Circle,
Box,
_Count,
};
class PhysicsObject
{
public:
virtual ObjectType type() const = 0;
};
class Circle : public PhysicsObject
{
public:
static const ObjectType MY_TYPE = ObjectType::Circle;
ObjectType type() const override { return MY_TYPE; }
};
class Box : public PhysicsObject
{
public:
static const ObjectType MY_TYPE = ObjectType::Box;
ObjectType type() const override { return MY_TYPE; }
};
Next, you have your collision resolution functions, they have to be implemented depending on the shapes, of course.
void ResolveCircleCircle(Circle* c1, Circle* c2)
{
std::cout << "Circle-Circle" << std::endl;
}
void ResolveCircleBox(Circle* c, Box* b)
{
std::cout << "Circle-Box" << std::endl;
}
void ResolveBoxBox(Box* b1, Box* b2)
{
std::cout << "Box-Box" << std::endl;
}
Note, that we only have Circle-Box here, no Box-Circle, as I assume their collision is detected in the same way. More on the Box-Circle collision case later.
Now to the core part, the function table:
std::function<void(PhysicsObject*,PhysicsObject*)>
ResolveFunctionTable[(int)(ObjectType::_Count)][(int)(ObjectType::_Count)];
REGISTER_RESOLVE_FUNCTION(Circle, Circle, &ResolveCircleCircle);
REGISTER_RESOLVE_FUNCTION(Circle, Box, &ResolveCircleBox);
REGISTER_RESOLVE_FUNCTION(Box, Box, &ResolveBoxBox);
The table itself is a 2d array of std::functions. Note, that those functions accept pointers to PhysicsObject, not the derived classes. Then, we use some macros for easy registration. Of course, the respective code could be written by hand and I am quite aware of the fact that the use of macros is typically considered bad habit. However, in my opinion, these sorts of things are what macros are good for and as long as you use meaningful names that do not clutter your global namespace, they are acceptable. Notice again that only Circle-Box is registered, not the other way round.
Now to the fancy macro:
#define CONCAT2(x,y) x##y
#define CONCAT(x,y) CONCAT2(x,y)
#define REGISTER_RESOLVE_FUNCTION(o1,o2,fn) \
const bool CONCAT(__reg_, __LINE__) = []() { \
int o1type = static_cast<int>(o1::MY_TYPE); \
int o2type = static_cast<int>(o2::MY_TYPE); \
assert(o1type <= o2type); \
assert(!ResolveFunctionTable[o1type][o2type]); \
ResolveFunctionTable[o1type][o2type] = \
[](PhysicsObject* p1, PhysicsObject* p2) { \
(*fn)(static_cast<o1*>(p1), static_cast<o2*>(p2)); \
}; \
return true; \
}();
The macro defines a uniquely named variable (using the line number), but this variable merely serves to get the code inside the initializing lambda function to be executed. The types (from the ObjectType enum) of the passed two arguments (these are the concrete classes Box and Circle) are taken and used to index the table. The entire mechanism assumes that there is a total order on the types (as defined in the enum) and checks that a function for Circle-Box collision is indeed registered for the arguments in this order. The assert tells you if you are doing it wrong (accidentally registering Box-Circle). Then a lambda function is registered inside the table for this particular pair of types. The function itself takes two arguments of type PhysicsObject* and casts them to the concrete types before invoking the registered function.
Next, we can have a look at how the table is then used. It is now easy to implement a single function that checks collision of any two PhysicsObjects:
void ResolveCollision(PhysicsObject* p1, PhysicsObject* p2)
{
int p1type = static_cast<int>(p1->type());
int p2type = static_cast<int>(p2->type());
if(p1type > p2type) {
std::swap(p1type, p2type);
std::swap(p1, p2);
}
assert(ResolveFunctionTable[p1type][p2type]);
ResolveFunctionTable[p1type][p2type](p1, p2);
}
It takes the dynamic types of the argument and passes them to the function registered for those respective types inside the ResolveFunctionTable. Notice, that the arguments are swapped if they are not in order. Thus you are free to invoke ResolveCollision with Box and Circle and it will then internally invoke the function registered for Circle-Box collision.
Lastly, I will give an example of how to use it:
int main(int argc, char* argv[])
{
Box box;
Circle circle;
ResolveCollision(&box, &box);
ResolveCollision(&box, &circle);
ResolveCollision(&circle, &box);
ResolveCollision(&circle, &circle);
}
Easy, isn't it? See this for a working implementation of the above.
Now, what is the advantage of this approach? The above code is basically all you need to support an arbitrary number of shapes. Let's say you are about to add a Triangle. All you have to do is:
Add an entry Triangle to the ObjectType enum.
Implement your ResolveTriangleXXX functions, but you have to do this in all cases.
Register them to your table using the macro: REGISTER_RESOLVE_FUNCTION(Triangle, Triangle, &ResolveTriangleTriangle);
That's it. No need to add further methods to PhysicsObject, no need to implement methods in all existing types.
I am aware of some 'flaws' of this approach like using macros, having a central enum of all types and relying on a global table. The latter case might lead to some trouble if the shape classes are built into multiple shared libraries. However, in my humble opinion, this approach is quite practical (except for very special use cases) since it does not lead to the explosion of code as is the case with other approaches (e.g. double-dispatch).

How to reference a variable without knowing the specific type?

I'm fairly new to C++, and still trying to get my head around some of the finer points of intermediate-level concepts such as templates/writing generic code. I'm writing an application using OpenSceneGraph (OSG), and basically this is what I'm trying to do:
I want to have a general element class that can handle any number of different element 'types'
Each instance of the general element class should contain a different shape (depending on the type)
The different element types (and the shapes they're mapped to) will only be discovered at run-time, because they're going to depend on source data - e.g. there could be 6 different element types that are all represented by boxes of different sizes. Or there could be 3 different element types - one Box, one Cylinder, one Cone.
Some background info about OSG to explain the source of my issue:
osg::Box and osg::Cylinder are both kinds of osg::Shape
both derived types have identical methods, getCenter
even though you can do osg::Shape myShape = osg::Box(); you can't then say myShape.getCenter(); - doesn't work on osg::Shape objects.
Here's an example of what I'm trying to do:
class MyClass {
private:
// ???? How to reference 'shape' ??
public:
MyClass(string _type) {
// This is for example purposes. Eventually types & mappings will be discovered at run-time.
if (_type == "FOO") {
shape = new osg::Box();
} else if (_type == "BAR") {
shape = new osg::Sphere();
}
}
/*
???? How to handle getShape()??
*/
}
int main() {
string readFromData = "FOO";
MyClass* myFoo (readFromData);
string alsoFromData = "BAR";
MyClass* myBar (alsoFromData);
osg::Vec3f fooCenter = myFoo->getShape()->getCenter();
osg::Vec3f barCenter = myBar->getShape()->getCenter();
}
I've tried a few different approaches but haven't quite been able to work it out:
creating a MyShape class that extends osg::Shape, and has a virtual function header for getCenter - but this makes MyShape an abstract class that cannot be instantiated.
template<typedef T> class MyClass... - but if we only discover the type & shape mappings at runtime, then what goes in the angle brackets throughout the rest of my code? e.g.: MyClass<?????????>* myFoo;
using boost::any to store the shape internally - but same issue basically. How do you define a getShape function that could return a pointer to one of several different types?
I can't find any previous questions that deal with this type of scenario specifically (sorry if I missed one!). If anyone can help me it'd be super awesome!
OSG supplies a osg::ShapeVisitor class for situations such as this one. Create a CenterFinderVisitor class that extends osg::ShapeVisitor, overriding each of its virtual member functions to retrieve the center of the corresponding shape. Pass an instance of the CenterFinderVisitor to the osg::ShapeVisitor's accept() member function on the shape instance that you store by pointer inside your class to retrieve the center, like this:
struct CenterFinderVisitor : public osg::ShapeVisitor {
Vec3 center;
virtual void apply (Sphere &s) { center = s.getCenter(); }
virtual void apply (Box &b){ center = b.getCenter(); }
// ...and so on for other shapes
};
Now you can implement your getCenter() method as follows:
class MyClass {
private:
osg::Shape *shape;
public:
MyClass(string _type) {
// This is for example purposes. Eventually types & mappings will be discovered at run-time.
if (_type == "FOO") {
shape = new osg::Box();
} else if (_type == "BAR") {
shape = new osg::Sphere();
}
}
Vec3 getShapeCenter() {
CenterFinderVisitor cf;
shape->accept(cf);
return cf.center;
}
};
If you are not familiar with the visitor pattern, read this article on wikipedia.
This is a classic OOP question.
Have shape base class and have all shapes inherit from it.
In shape declare all functions (pure virtual or just virtual) you want a shape to have:
class shape {
public:
shape(string _name) : name(_name) {}
virtual ~shape(); // virtual desructor
virtual POINT getCenter() = NULL;
virtual getName() { return name; } // example - functionality in base class
protected:
string name;
};
class rectangle : public shape {
{
rectangle() : shape("rectangle") {}
virtual POINT getCenter() { return /* do math here :) */ }
};
In your MyClass class, have a pointer/ref to a shape type.

How can I iterate over a vector of base class objects?

I have an problem where we need to have a number of shapes, such as a Circle and Square which can be position on a flat, 2 dimensional plane. All shapes, such as Circle and Square inherit from an abstact base class Shape; as such I have a vector of pointers to shapes.
However, I need to be able to iterate over the plane and find any shapes which collide, such that they are intersecting or touching. If I get a shape from the vector, I don't know if it is a Square or a Circle because it has been sliced to the Shape base class.
How would I be best solving this problem?
#ifndef Plane_h
#define Plane_h
#include <vector>
#include "Shape.h"
class Plane {
public:
Plane(std::vector<Shape*>);
Plane(const Plane&);
~Plane();
void add(Shape*);
std::vector<Shape*> all() const;
protected:
std::vector<Shape*> shapes;
};
#endif
Your classes have not been sliced. This would result in a sliced object:
vector<Shape> vec;
Circle circ;
vec.push_back(circ);
http://en.wikipedia.org/wiki/Object_slicing
In your instance the instantiated objects remain whole and the pointers point to whole objects - but it is almost certainly true that in order to calculate intersections you will need to do some downcasting. While this is to be done as little as possible it's not a crime in itself.
Your best bet would be to provide a method in the base class to return a value indicating the object type - maybe use an enumeration - and use that to downcast a particular Shape pointer or reference to a pointer/reference to the correct derived type.
An abstract method in the base Shape class like bool Intersects( const Shape& obj ) could be overridden by the derived classes, the overrides downcasting the parameter to the correct derived type.
Alternatively you might prefer to provide a global/static method taking two shapes, or privately implement that method and call it from the instance method Intersects()
( Detecting the intersections is not exactly a trivial task. :-) )
You have to use polymorphism. Add a virtual method on your Shape class:
class Shape {
...
virtual bool intersects(Shape const* otherShape);
...
}
Then you implement it for each different shape. Then if it's used like:
Shape* A = getShapeA();
Shape* B = getShapeB();
if (A->intersects(B))
doSomething();
The correct version is called, i.e if A is a Circle, Circle::intersects is called. But in there, you still don't know what shape B actually is. You can find this out by trying to do a dynamic cast:
Circle* circle = dynamic_cast<Circle*>(otherShape);
if (circle)
intersectsCircle(circle);
Here is another method, that does not need dynamic casts (or any explicit cast at all), or an ugly enum listing the subclasses. It is based on double dispatch, which basically works by going through two virtual methods in order to determine the types of the two objects you want to work on.
#include <iostream>
using namespace std;
class Circle;
class Square;
struct Shape
{
virtual void intersect(Shape* otherShape) = 0;
virtual void intersect(Circle* otherCircle) = 0;
virtual void intersect(Square* otherSquare) = 0;
};
struct Circle : public Shape
{
virtual void intersect(Shape* otherShape)
{
otherShape->intersect(this);
}
virtual void intersect(Circle* otherCircle)
{
cout << "Intersecting Circle with Circle" << endl;
}
virtual void intersect(Square* otherSquare)
{
cout << "Intersecting Circle with Square" << endl;
}
};
struct Square : public Shape
{
virtual void intersect(Shape* otherShape)
{
otherShape->intersect(this);
}
virtual void intersect(Circle* otherCircle)
{
otherCircle->intersect(this);
}
virtual void intersect(Square* otherSquare)
{
cout << "Intersecting Square with Square" << endl;
}
};
int main()
{
Circle circle;
Square square;
circle.intersect(&square);
Shape* shapeA = &circle;
Shape* shapeB = &square;
shapeA->intersect(shapeA);
shapeA->intersect(shapeB);
shapeB->intersect(shapeA);
shapeB->intersect(shapeB);
}
Note that here you still have to list all possible subclasses within the base class, but in this case in the form of overloads of the intersect for each base class. If you fail to add all (say, you make a class Triangle : public Shape, but no Shape::intersect(Triangle*)), you end up with infinite call loops.
Also note that in this example I did a 'triple' dispatch, so I don't have to implement the logic to intersect a Circle with a Square twice.

Comparing Polymorphic Base Types in C++ without RTTI

I have some pointers to a base type of Shape. I want to compare these objects using the == operator. The == operator should obviously return false if the objects are of different derived type. If they are of the same derived type however the members of the derived type should then be compared.
I have read that using the C++ RTTI is bad practice and should only be used in rare and essential circumstances. As far as I can see this problem cannot be generally solved without using the RTTI. Each overloaded == operator would have to check the typeid, and if they are the same perform a dynamic_cast and compare the members. This seems like a common need. Is there some kind of idiom for this problem?
#include <iostream>
using namespace std;
class Shape {
public:
Shape() {}
virtual ~Shape() {}
virtual void draw() = 0;
virtual bool operator == (const Shape &Other) const = 0;
};
class Circle : public Shape {
public:
Circle() {}
virtual ~Circle() {}
virtual void draw() { cout << "Circle"; }
virtual bool operator == (const Shape &Other) const {
// If Shape is a Circle then compare radii
}
private:
int radius;
};
class Rectangle : public Shape {
public:
Rectangle() {}
virtual ~Rectangle() {}
virtual void draw() { cout << "Rectangle"; }
virtual bool operator == (const Shape &Other) const {
// If Shape is a Rectangle then compare width and height
}
private:
int width;
int height;
};
int main() {
Circle circle;
Rectangle rectangle;
Shape *Shape1 = &circle;
Shape *Shape2 = &rectangle;
(*Shape1) == (*Shape2); // Calls Circle ==
(*Shape2) == (*Shape1); // Calls Rectangle ==
}
Use the RTTI.
Use typeid, but use static_cast rather than dynamic_cast.
From a design point of view, I'd say that this is exactly what RTTI is for, any alternative solutions will, by necessity, be uglier.
virtual bool operator == (const Shape &Other) const {
if(typeid(Other) == typeid(*this))
{
const Circle& other = static_cast<const Circle&>(Other);
// ...
}
else
return false;
}
From a performance point of view:
typeid tends to be cheap, a simple lookup of a pointer stored in the virtual table. You can cheaply compare dynamic types for equality.
Then, once you know you have the right type, you can safely use static_cast.
dynamic_cast has a reputation for being slow (that is, slow as in "compared to virtual function calls", not slow as in "compared to a cast in java"), because it will also analyze the class hierarchy to deal with inheritance (and multiple inheritance, too). You don't need to deal with that here.
Of course it can be done without using typeid and casting. But it is a bit cumbersome so you must decide if it's worth doing.
Version one - double visitors
Use visitor pattern
class ShapeVisitor
{
public:
virtual void visitCircle(Circle const &) = 0;
virtual void visitRectangle(Rectangle const &) = 0;
// other shapes
}
To class Shape add
virtual void acceptVisitor(ShapeVisitor &) = 0;
And visitors
class CircleComparingVisitor : public ShapeVisitor
{
Circle const & lhs; // shorthand for left hand side
bool equal; // result of comparison
public:
CircleComparingVisitor(Circle const & circle):lhs(circle), equal(false){}
virtual void visitCircle(Circle const & rhs) {equal = lhs.radius == rhs.radius;}
virtual void visitRectangle(Rectangle const &) {}
// other shapes
bool isEqual() const {return equal;}
}
// other shapes analogically
class ShapeComparingVisitor
{
Shape const & rhs; // right hand side
bool equal;
public:
ShapeComparingVisitor(Shape const & rhs):rhs(rhs), equal(false) {}
bool isEqual() const {return equal;}
virtual void visitCircle(Circle const & lhs)
{
CircleComparingVisitor visitor(lhs);
rhs.accept(visitor);
equal = visitor.isEqual();
}
virtual void visitRectangle(Rectangle const & lhs)
{
RectangleComparingVisitor visitor(lhs);
rhs.accept(visitor);
equal = visitor.isEqual();
}
}
Finally operator== no need to be virtual
bool Shape::operator==(const Shape &rhs) const
{
ShapeComparingVisitor visitor(rhs);
this->accept(visitor);
return visitor->isEqual();
}
Second thought - operator== may be virtual and use a proper comparing visitor - so you can get rid of ShapeComparingVisitor
Version two - double dispatching
You add to Shape
virtual bool compareToCircle(Circle const &) const == 0;
virtual bool compareToRectangle(Rectangle const &) const == 0;
And implement in specific shapes
Now for example
bool Circle::operator==(Shape const & rhs) const
{
return rhs.compareToCircle(*this);
}
This is exactly what RTTI is for. At compile time all you know is that it's a Shape&, so you simply have to do a runtime check to see what derived type it actually is before you can make a meaningful comparison. I'm not aware of any other way to do it without violating polymorphism.
You could define many free functions for operator == for different derived type combinations, but it then wouldn't have polymorphic behaviour as you're presumably handling these via Shape& pointers so even the calling code doesn't actually know what type the objects are.
Thus, RTTI is (almost) unavoidable here, and indeed this kind of scenario is exactly why RTTI exists. It's only considered bad practice in some cases because it adds a certain fragility (you have to make sure you handle when things aren't of a type you know how to deal with, because anybody could come along and make a new subclass of Shape), and it adds a runtime cost. But you're already paying a runtime cost by using virtual methods.
I say 'almost unavoidable' because you could probably concoct some system which made further virtual method calls on the object passed in to operator == to get the right kind of comparison behaviour, but in practical terms another virtual method lookup (remember, virtual methods also have a runtime performance penalty because the compiler has no idea which implementation will get called so can't put in a concrete function address) is probably no faster than the cost of the RTTI.
If anybody knows a way to do it without that cost at all, I'd love to see it.
My feeling is that there is a fundamental violation of the Liskov substitution principle going on here, as you're digging into the internal representations of the objects. However if you're happy to expose the internal representation of your objects (or you have to do so for other reasons) then something like this will work.
class Shape
{
virtual void std::string serialize() const =0;
bool operator==( const Shape & s )
{
return this.serialize() == s.serialize();
}
};

Looking for a better way than virtual inheritance in C++

OK, I have a somewhat complicated system in C++. In a nutshell, I need to add a method to a third party abstract base class. The third party also provides a ton of derived classes that also need the new functionality.
I'm using a library that provides a standard Shape interface, as well as some common shapes.
class Shape
{
public:
Shape(position);
virtual ~Shape();
virtual position GetPosition() const;
virtual void SetPosition(position);
virtual double GetPerimeter() const = 0;
private: ...
};
class Square : public Shape
{
public:
Square(position, side_length);
...
};
class Circle, Rectangle, Hexagon, etc
Now, here's my problem. I want the Shape class to also include a GetArea() function. So it seems like I should just do a:
class ImprovedShape : public virtual Shape
{
virtual double GetArea() const = 0;
};
class ImprovedSquare : public Square, public ImprovedShape
{
...
}
And then I go and make an ImprovedSquare that inherits from ImprovedShape and Square. Well, as you can see, I have now created the dreaded diamond inheritance problem. This would easily be fixed if the third party library used virtual inheritance for their Square, Circle, etc. However, getting them to do that isn't a reasonable option.
So, what do you do when you need to add a little functionality to an interface defined in a library? Is there a good answer?
Thanks!
Why does this class need to derive from shape?
class ImprovedShape : public virtual Shape
{
virtual double GetArea() const = 0;
};
Why not just have
class ThingWithArea
{
virtual double GetArea() const = 0;
};
ImprovedSquare is a Shape and is a ThingWithArea
We had a very similar problem in a project and we solved it by just NOT deriving ImprovedShape from Shape. If you need Shape functionality in ImprovedShape you can dynamic_cast, knowing that your cast will always work. And the rest is just like in your example.
I suppose the facade pattern should do the trick.
Wrap the 3rd party interface into an interface of your own, and your application's code works with the wrapper interface rather than the 3rd party interface. That way you've nicely insulated changes in the uncontrolled 3rd party interface as well.
Perhaps you should read up on proper inheritance, and conclude that ImprovedShape does not need to inherit from Shape but instead can use Shape for its drawing functionality, similar to the discussion in point 21.12 on that FAQ on how a SortedList doesn't have to inherit from List even if it wants to provide the same functionality, it can simply use a List.
In a similar fashion, ImprovedShape can use a Shape to do it's Shape things.
Possibly a use for the decorator pattern? [http://en.wikipedia.org/wiki/Decorator_pattern][1]
Is it possible to do a completely different approach - using templates and meta-programming techniques? If you're not constrained to not using templates, this could provide an elegant solution. Only ImprovedShape and ImprovedSquare change:
template <typename ShapePolicy>
class ImprovedShape : public ShapePolicy
{
public:
virtual double GetArea();
ImprovedShape(void);
virtual ~ImprovedShape(void);
protected:
ShapePolicy shape;
//...
};
and the ImprovedSquare becomes:
class ImprovedSquare : public ImprovedShape<Square>
{
public:
ImprovedSquare(void);
~ImprovedSquare(void);
// ...
};
You'll avoid the diamond inheritance, getting both the inheritance from your original Shape (through the policy class) as well as the added functionality you want.
Another take on meta-programming/mixin, this time a bit influenced by traits.
It assumes that calculating area is something you want to add based on exposed properties; you could do something which kept with encapsulation, it that is a goal, rather than modularisation. But then you have to write a GetArea for every sub-type, rather than using a polymorphic one where possible. Whether that's worthwhile depends on how committed you are to encapsulation, and whether there are base classes in your library you could exploit common behaviour of, like RectangularShape below
#import <iostream>
using namespace std;
// base types
class Shape {
public:
Shape () {}
virtual ~Shape () { }
virtual void DoShapyStuff () const = 0;
};
class RectangularShape : public Shape {
public:
RectangularShape () { }
virtual double GetHeight () const = 0 ;
virtual double GetWidth () const = 0 ;
};
class Square : public RectangularShape {
public:
Square () { }
virtual void DoShapyStuff () const
{
cout << "I\'m a square." << endl;
}
virtual double GetHeight () const { return 10.0; }
virtual double GetWidth () const { return 10.0; }
};
class Rect : public RectangularShape {
public:
Rect () { }
virtual void DoShapyStuff () const
{
cout << "I\'m a rectangle." << endl;
}
virtual double GetHeight () const { return 9.0; }
virtual double GetWidth () const { return 16.0; }
};
// extension has a cast to Shape rather than extending Shape
class HasArea {
public:
virtual double GetArea () const = 0;
virtual Shape& AsShape () = 0;
virtual const Shape& AsShape () const = 0;
operator Shape& ()
{
return AsShape();
}
operator const Shape& () const
{
return AsShape();
}
};
template<class S> struct AreaOf { };
// you have to have the declaration before the ShapeWithArea
// template if you want to use polymorphic behaviour, which
// is a bit clunky
static double GetArea (const RectangularShape& shape)
{
return shape.GetWidth() * shape.GetHeight();
}
template <class S>
class ShapeWithArea : public S, public HasArea {
public:
virtual double GetArea () const
{
return ::GetArea(*this);
}
virtual Shape& AsShape () { return *this; }
virtual const Shape& AsShape () const { return *this; }
};
// don't have to write two implementations of GetArea
// as we use the GetArea for the super type
typedef ShapeWithArea<Square> ImprovedSquare;
typedef ShapeWithArea<Rect> ImprovedRect;
void Demo (const HasArea& hasArea)
{
const Shape& shape(hasArea);
shape.DoShapyStuff();
cout << "Area = " << hasArea.GetArea() << endl;
}
int main ()
{
ImprovedSquare square;
ImprovedRect rect;
Demo(square);
Demo(rect);
return 0;
}
Dave Hillier's approach is the right one. Separate GetArea() into its own interface:
class ThingWithArea
{
public:
virtual double GetArea() const = 0;
};
If the designers of Shape had done the right thing and made it a pure interface,
and the public interfaces of the concrete classes were powerful enough, you could
have instances of concrete classes as members. This is how you get SquareWithArea
(ImprovedSquare is a poor name) being a Shape and a ThingWithArea:
class SquareWithArea : public Shape, public ThingWithArea
{
public:
double GetPerimeter() const { return square.GetPerimeter(); }
double GetArea() const { /* do stuff with square */ }
private:
Square square;
};
Unfortunately, the Shape designers put some implementation into Shape, and you
would end up carrying two copies of it per SquareWithArea, just like in
the diamond you originally proposed.
This pretty much forces you into the most tightly coupled, and therefore least
desirable, solution:
class SquareWithArea : public Square, public ThingWithArea
{
};
These days, it's considered bad form to derive from concrete classes in C++.
It's hard to find a really good explanation why you shouldn't. Usually, people
cite Meyers's More Effective C++ Item 33, which points out the impossibility
of writing a decent operator=() among other things. Probably, then, you should
never do it for classes with value semantics. Another pitfall is where the
concrete class doesn't have a virtual destructor (this is why you should
never publicly derive from STL containers). Neither applies here. The poster
who condescendingly sent you to the C++ faq to learn about inheritance is
wrong - adding GetArea() does not violate Liskov substitutability. About
the only risk I can see comes from overriding virtual functions in the
concrete classes, when the implementer later changes the name and silently breaks
your code.
In summary, I think you can derive from Square with a clear conscience.
(As a consolation, you won't have to write all the forwarding functions for
the Shape interface).
Now for the problem of functions which need both interfaces. I don't like
unnecessary dynamic_casts. Instead, make the function take references to
both interfaces and pass references to the same object for both at the call site:
void PrintPerimeterAndArea(const Shape& s, const ThingWithArea& a)
{
cout << s.GetPerimeter() << endl;
cout << a.GetArea() << endl;
}
// ...
SquareWithArea swa;
PrintPerimeterAndArea(swa, swa);
All PrintPerimeterAndArea() needs to do its job is a source of perimeter and a
source of area. It is not its concern that these happen to be implemented
as member functions on the same object instance. Conceivably, the area could
be supplied by some numerical integration engine between it and the Shape.
This gets us to the only case where I would consider passing in one reference
and getting the other by dynamic_cast - where it's important that the two
references are to the same object instance. Here's a very contrived example:
void hardcopy(const Shape& s, const ThingWithArea& a)
{
Printer p;
if (p.HasEnoughInk(a.GetArea()))
{
s.print(p);
}
}
Even then, I would probably prefer to send in two references rather than
dynamic_cast. I would rely on a sane overall system design to eliminate the
possibility of bits of two different instances being fed to functions like this.
GetArea() need not be a member. It could be templated function, so that you can invoke it for any Shape.
Something like:
template <class ShapeType, class AreaFunctor>
int GetArea(const ShapeType& shape, AreaFunctor func);
The STL min, max functions can be thought of as an analogy for your case. You can find a min and max for an array/vector of objects given a comparator function. Like wise, you can derive the area of any given shape provided the function to compute the area.
There exists a solution to your problem, as I understood the question. Use the addapter-pattern. The adapter pattern is used to add functionality to a specific class or to exchange particular behaviour (i.e. methods). Considering the scenario you painted:
class ShapeWithArea : public Shape
{
protected:
Shape* shape_;
public:
virtual ~ShapeWithArea();
virtual position GetPosition() const { return shape_->GetPosition(); }
virtual void SetPosition(position) { shape_->SetPosition(); }
virtual double GetPerimeter() const { return shape_->GetPerimeter(); }
ShapeWithArea (Shape* shape) : shape_(shape) {}
virtual double getArea (void) const = 0;
};
The Adapter-Pattern is meant to adapt the behaviour or functionality of a class. You can use it to
change the behaviour of a class, by not forwarding but reimplementing methods.
add behaviour to a class, by adding methods.
How does it change behaviour? When you supply an object of type base to a method, you can also supply the adapted class. The object will behave as you instructed it to, the actor on the object will only care about the interface of the base class. You can apply this adaptor to any derivate of Shape.