C++ : Add a method to a base class interface - c++

Suppose I have a third-party library with a large polymorphic class hierarchy:
Base => Sub1, Sub2, Sub3 => SubSub1, SubSub2 ... etc.
I can take a bunch of objects from various subclasses within the hierarchy, stuff pointers of type *Base into a STL container, then use an iterator to call a specific base class method on each.
What if I want to add a new virtual method to the base class then do the same thing, calling that method for each object in the container?
The base class is part of a library, so I can't just add a new virtual method to it. Deriving a subclass does not work because I lose access to all of the other subclasses. In Java, I would create an interface and have each of the relevant subclasses implement it. I am not sure how best to handle this problem in C++, though.
EDIT:
(1) The visitor pattern suggested below would be a great solution, but requires that the original base class be written with that pattern in mind.
(2) The plug-in pattern suggested below is a generalized solution that works, but can be very slow in certain use-cases.
(3) Deriving a subclass from Base, then refactoring the whole hierarchy so that it derives from this subclass is cumbersome and might break if the library code is upgraded.
(4) I try to avoid multiple inheritance, but it works in my (simple) use-case:
#include <third_party_lib.h>
class MyBase {
public:
virtual ~MyBase() {}
virtual void myMethod() = 0;
};
class MySub1 : public ThirdPartyLib::Sub1, MyBase {
public:
void myMethod() { /*...*/ }
};
class MySub2 : public ThirdPartyLib::Sub2, MyBase {
public:
void myMethod() { /*...*/ }
};
void doSomething() {
std::vector<ThirdPartyLib::Base*> vec;
// fill vector with instances of MySub1, MySub2, etc
for (auto libHandle : vec) {
// call a method from the library class hierarchy ...
libHandle->libraryClassMethod();
// call the virtual method declared in MyBase ...
MyBase* myHandle = dynamic_cast<MyBase*>(libHandle);
if (myHandle) {
myHandle->myMethod();
} else {
// deal with error
}
}
}

If you don't have the option of modifying the base class, you can use a pattern that I call the plugin pattern.
You create a global function or a function in an appropriate namespace to perform operations given an object of type Base.
You provide a mechanism where the implementation for a derived type can register itself.
In the implementation of the function, you iterate over the registered functions/functors to check whether there is an implementation for the type of the object. If yes, you perform the operation. Otherwise, you report an error.
Let's say you have:
struct Shape
{
// Shape details
};
struct Triangle : public Shape
{
// Triangle details
};
struct Rectangle : public Shape
{
// Rectangle details
};
For the purpose of illustration, let's say that Shape does not have an interface to compute the area of Shape objects. To implement the ability to compute the area of a shape, you can do this:
Create a function to get area of a Shape.
extern double getArea(Shape const& shape);
Add a registration mechanism for functions that can compute area of Shapes.
typedef double (*GetAreaFunction)(Shape const& shape, bool& isSuccess);
extern void registerGetAreaFunction(GetAreaFunction fun);
Implement the core functions in a .cc file.
static std::set<GetAreaFunction>& getRegistry()
{
static std::set<GetAreaFunction> registry;
return registry;
}
void registerGetAreaFunction(GetAreaFunction fun)
{
getRegistry().insert(fun);
}
double getArea(Shape const& shape)
{
double area = 0.0;
for ( auto fun: getRegistry() )
{
bool isSuccess = false;
area = fun(shape, isSuccess);
if ( isSuccess )
{
return area;
}
}
// There is no function to compute the area of the given shape.
// Throw an exception or devise another mechanism to deal with it.
}
Add functions to compute the area of Triangle and Rectangle, wherever it seems appropriate in your code base.
double getArea(Triangle const& triangle)
{
// Do the needful and return the area.
}
double getArea(Rectangle const& rectangle)
{
// Do the needful and return the area.
}
Add a function that can be registered with the core API.
double getAreaWrapper(Shape const& shape, bool& isSuccess)
{
// Do dynamic_cast to see if we can deal with the shape.
// Try Triangle first.
Triangle const* trianglePtr = dynamic_cast<Triangle const*>(&shape);
if ( trianglePtr )
{
isSuccess = true;
return getArea(*trianglePtr);
}
// Try Rectangle next.
Rectangle const* rectanglePtr = dynamic_cast<Rectangle const*>(&shape);
if ( rectanglePtr )
{
isSuccess = true;
return getArea(*rectanglePtr );
}
// Don't know how to deal with the given shape.
isSuccess = false;
return 0.0;
}
Register the function with the core.
registerGetAreaFunction(getAreaWrapper);
Pros
This is an elaborate method for avoiding a long if-else block in one function.
It avoids hard dependencies in the core to deal with derived types.
Cons
Most important - don't use this for any function that needs to get called millions of times. That will kill performance.

There are actually two ways to accomplish this.
1) Add a class ( say base1 ) for which base would be your "base" class in library. Then let all other classes to derive from base1 rather than base.
2) Use multiple inheritance. You add another class "base1" , and then let other derived classes inherit both from "base" as well as "base1".
I would prefer former approach as multiple inheritance has it's own bottlenecks.

Related

Avoid downcasting in an inherited tree class

I'm relatively new to C++ and I'm right now facing a point in my design where I cannot seem to avoid downcasting. I know this is usually a sign of bad design, so I would like to know what would be a better way to do this.
I have a class Frame that represents geometrical frame trees and allows geometrical transformations between them:
class Frame
{
private:
Frame *_parent;
std::vector<Frame*> _children;
public:
Frame* getParent() const;
std::vector<Frame*> getChildren() const;
... (extra methods for geometrical transformations)
}
I want now to create a new Frame subclass, MechanicalFrame, that adds some functionality to deal with dynamical properties.
class MechanicalFrame
{
private:
double mass;
...
public:
void compute();
}
My problem is that, the "compute" method needs to implement some recursive logic, so it would contain something like this:
MechanicalFrame::compute()
{
for element in getChildren():
element.compute();
}
However, since getChildren returns a vector of Frame* and not MechanicalFrame*, I would need to make a static_cast at this point. I've given the problem a lot of thought, but none of the solutions I've found are fully satisfying to me:
Solution 1) Static cast: somehow it indicates bad design
Solution 2) Add the compute method to the base class (Frame) with a dummy implementation, i.e., throwing an exception: it seems unnatural to force the implementation of the parent class based on the derived class.
Solution 3) Split totally MechanicalFrame from Frame: this would mean reimplementing many of the functionalities already available in Frame.
Any help would be very appreciated.
Many thanks in advance :)
Use polymorphic behaviour, use your Solution 2)
You can follow below pattern (Interface -> Base class -> Derived class)
class IFrame
{
public:
virtual void compute()=0;
}
class Frame:public IFrame
{
public:
virtual void compute() {/*nothing to do*/}
}
class MechanicalFrame:public Frame
{
public:
virtual void compute() {/*your implementation with mass*/}
}
If you are sure that all the Frame* pointers in MechanicalFrame::getChildren() are pointing to MechanicalFrame instances, I don't see any problem with static_cast. Make sure you use dynamic_cast + assert in debug builds to catch mistakes.
void MechanicalFrame::compute()
{
for(auto frame_ptr : getChildren())
{
downcast<MechanicalFrame*>(frame_ptr)->compute();
}
}
Where downcast is something like:
template <typename TOut, typename T>
auto downcast(T* ptr)
{
static_assert(std::is_base_of<T, TOut>{});
assert(ptr != nullptr);
assert(dynamic_cast<TOut>(ptr) == ptr);
return static_cast<TOut>(ptr);
}
(For a more thorough implementation of downcast see my Meeting C++ 2015 lightning talk "Meaningful casts" or my current implementation in vrm_core.)
Notice that there's a performance advantage here, as you avoid virtual dispatch. Play around with this snippet on gcc.godbolt.org to see differences in the generated assembly.
Another option is to use the Visitor pattern:
class Frame;
class MechanicalFrame;
class FrameVisitor
{
public:
virtual ~FrameVisitor() = default;
virtual void visit(Frame&) = 0;
virtual void visit(MechanicalFrame&) = 0;
};
class Frame
{
public:
virtual void accept(FrameVisitor& visitor)
{
visitor.visit(*this);
}
void acceptRecursive(FrameVisitor& visitor)
{
accept(visitor);
for (Frame* child : getChildren())
{
child->acceptRecursive(visitor);
}
}
...
};
class MechanicalFrame : public Frame
{
public:
virtual void accept(FrameVisitor& visitor) override
{
visitor.visit(*this);
}
...
};
Then the client code will be:
class ConcreteVisitor : public FrameVisitor
{
public:
virtual void visit(Frame& frame) override
{
// Deal with Frame (not a subclass) object.
}
virtual void visit(MechanicalFrame& frame) override
{
// Deal with MechanicalFrame object.
}
};
Frame root = ...;
ConcreteVisitor visitor;
root.acceptRecursive(visitor);
In general, the Visitor pattern allows you to traverse a hierarchy of heterogeneous objects and perform operations on them without type casting. It's most useful when the number of operations is expected to grow while your type hierarchy is more or less stable.
Since you're asking for new ideas, I will not explain in detail anything you written about in solutions 1-3.
You could add extra functionality to the MechanicalFrame class, splitting its children of MechanicalFrame class and all other classes, like this:
class Frame {
public:
std::vector<Frame*> getChildren(); // returns children
void addChild(Frame* child); // adds child to children
private:
std::vector<Frame*> children;
}
class MechanicalFrame : public Frame {
public:
void compute();
std::vector<MechanicalFrame*> getMechanicalChildren(); // returns mechanical_children
void addChild(MechanicalFrame* child); // adds child to mechanical_children
private:
std::vector<MechanicalFrame*> mechanical_children;
}
One possible implementation of compute is the following:
void MechanicalFrame::compute() {
...
for (auto* child : getMechanicalChildren()) {
child->compute();
}
}
UP: As far as I understand, one of the problems with casts is that the code starts behaving very differently depending on the actual class of the object, and we cannot substitute the parent class object with child class (see Liskov principle). The approach described in this answer actually changes the principle of using the "mechanicity" of your Frames, allowing adding MechanicalFrame children in such a way that they're ignored in compute method.

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.

Access members of derived class through base class pointer C++

Is there any way to have a general code access members of derived class through base class pointer? Or any other way around this?
Let's say I have a class Shape. I have classes Square and Triangle which inherit it. Both have their own private members which have nothing to do with each other so there is no point in having them in the base class. Now, what if I need to write a class into a file, but I don't know if the class is Square or Triangle until the moment I need to write it in the file?
I've been trying to figure out how to solve this problem. The worst case solution would be to write the data of both Square AND Triangle into a file, add an identifier (Triangle or Square) for both reading and writing and have a small parser put the class together when loading data. This would be inefficient and waste of time.
I was wondering if there is some trick or design pattern or anything that can help with the situation.
This serialization should be done using virtual functions. Define a function in the base class that shall serialize the object. The Triangle and the Square overrides this functions and write
the identifier
all data that should be serialized
You may implement the common part in the base class if appropriate.
When you want load the file you will need factory method that creates the class instance corresponding to the identifier. The new instance virtual deserialize method must be called to load the actual data.
You can have a pure virtual getter in your Base Class. and all your Derived classes will override that. like this
class Shape{
public:
virtual int data() const = 0;
};
class Square: public Shape{
private:
int _member;
public:
virtual int data() const{
//do something with private members and return it
return _member;
};
};
I think there is no direct way to remove this overhead. Normally this is done by a two things. First of all, the object needs a serialization mechanism:
To serialize things, one need a location to serialize to. In this case, we will do this using a data container, but this can also be a file stream or a container class. Serialization can be made from within the object or from outside, most easy implementation is now from the inner side:
The simple serialization part:
class Shape{
public:
virtual void serialize( Datacontainer &o ) const = 0;
};
class Triangle: public Shape{
void serialize( Datacontainer &o ) const{
o.add('T');
o.add(corners);
}
std::vector<point> corners;
}
class Circle: public Shape{
void serialize( Datacontainer &o ) const{
o.add('C');
o.add(center);
o.add(radius);
}
point center;
double radius;
}
During serialization, you can do this by using the basic class Shape:
Shape *tri = new Triangle;
tri->serialize( dataContainer or file );
Deserialization is not as easy, because you need to know the type. A good pattern for this is the Builder pattern. Despite this, we can implement a more C++ likely way to do this:
Add the following thing to all of your classes:
static Shape* createFrom( Datacontainer &o );
For eg. the Circle implementation:
Shape* Circle::createFrom( Datacontainer &o )
{
Circle *c = new Circle()
c->center = o.get();
c->radius = o.get();
}
This enables us to create a concrete instance, but we have a common function footprint for the method. Now one can implement a very easy builder like this one:
class ShapeBuilder
{
public:
static Shape* createShape( Datacontainer& o )
{
char id = o.get();
swith(id){
case 'T':
return Triangle::createFrom(o);
case 'C':
return Circle::createFrom(o);
}
}
}
You need to declare virtual methods in your base class, and have derived classes define them. If you want to save them to a file though - you will need a way to identify what specific class instance is in the file, since they may have different memory layouts.
Probably the best way is to do something like this. The basic patten is that you can put common code, that is guaranteed always to be the same for every derived class, in the base. Things that need to differ, put in a virtual function that the derived classes each implement differently.
class Shape {
virtual void writeSerialData(std::ostream &) const = 0;
public:
void writeToFile(const std::string &filename) const {
std::ofstream outfile(filename); // filename.c_str() in C++03
writeSerialData(outfile);
if (!outfile.close()) {
// report the error
}
}
virtual ~Shape() {}
};
class Square : public Shape {
double length;
virtual void writeSerialData(std::ostream &out) const {
out << "Square{" << length << '}';
}
public:
Square(double l) : length(l) {}
};
Now you have the next problem -- how do you read an object back from a file, without knowing in advance which derived class it is? For that you need a way to see the text Square and either (a) call a static function of the class Square that knows how to interpret the data or (b) instantiate the class Square by giving it the data to interpret. It's worth looking into Boost Serialization, or other serialization libraries, before you go too far down that path.

Multiple inheritance in C++ leading to difficulty overriding common functionality

In a C++ physics simulation, I have a class called Circle, and Square. These are Shapes, and have a method called push(), which applies force to it. There is then a special case of Circle, call it SpecialCircle, in which push() should exhibit slightly different properties. But in fact, there is also SpecialSquare() which should exhibit the same force properties. So I'd like to have an abstract base class called Shape which takes care of Circles and Squares, but then I'd also like an abstract base class called Special, which applies special properties to force().
What's the best way to design this class structure?
So far, I've got:
class Shape {
virtual void push();
};
class Circle : public Shape {};
class Square : public Shape {};
class Special {
virtual void push();
};
class SpecialCircle : public Circle, Special {};
class SpecialSquare : public Square, Special {};
Of course, the above won't compile, since Special::push() and Shape::push() conflict. I get "error: request for member ‘push’ is ambiguous", as expected.
How can I re-organize my class structure so that Circle and Square can share certain properties with each other, but SpecialCircle and SpecialSquare can still inherit from Shape, and also inherit modified functionality from Special?
Thanks.
ps., is this the diamond inheritance problem?
Another solution (it may or may not fit your needs, it depends on the details of your implementation):
Have the class Behavior, and let NormalBehavior and SpecialBehavior inherit from it.
Have the class Shape, and let Square and Circle inherit from it. Let Shape be an aggregate type, with a Behavior member (i.e. you pass a Behavior object to the various Shape constructors). In other words, let a Shape have a Behavior.
Delegate the actual differences in the behavior of shapes to methods of the Behavior hierarchy.
Conversely, you can:
Have the class PhysicalObject, and let NormalObject and SpecialObject inherit from it;
Have the class Shape, and let Square and Circle inherit from it;
Let a PhysicalObject have a Shape.
Prefer aggregation over inheritance. This is an application of the Bridge pattern. The advantage of this strategy with respect to having Square, SpecialSquare, Circle, and SpecialCircle, is that tomorrow you'll have to add Rectangle, Hexagon and so on, and for each shape you add you'll have to implement two classes (duplicated code is evil); this is, in my opinion, the real issue that Bridge addresses.
It's said that every problem in software can be solved by adding an additional layer of indirection.
Herb Sutter has an excellent article on how to solve your problem: Multiple Inheritance - Part III
In short, you use intermediate classes to 'rename' the virtual functions. As Herb says:
Renaming Virtual Functions
If the two inherited functions had different signatures, there would be no problem: We would just override them independently as usual. The trick, then, is to somehow change the signature of at least one of the two inherited functions.
The way to change a base class function's signature is to create an intermediate class which derives from the base class, declares a new virtual function, and overrides the inherited version to call the new function
Here's a long example using your classes:
class Shape {
public:
virtual void push() = 0;
};
class Circle : public Shape
{
public:
void push() {
printf( "Circle::push()\n");
}
};
class Square : public Shape
{
public:
void push() {
printf( "Square::push()\n");
}
};
class Special {
public:
virtual void push() = 0;
};
class Circle2: public Circle
{
public:
virtual void pushCircle() = 0;
void push() {
pushCircle();
}
};
class Square2: public Square
{
public:
virtual void pushSquare() = 0;
void push() {
pushSquare();
}
};
class Special2 : public Special
{
public:
virtual void pushSpecial() = 0;
void push() {
pushSpecial();
}
};
class SpecialCircle : public Circle2, public Special2
{
public:
void pushSpecial() {
printf( "SpecialCircle::pushSpecial()\n");
}
void pushCircle() {
printf( "SpecialCircle::pushCircle()\n");
}
};
class SpecialSquare : public Square2, public Special2
{
public:
void pushSpecial() {
printf( "SpecialSquare::pushSpecial()\n");
}
void pushSquare() {
printf( "SpecialSquare::pushSquare()\n");
}
};
int main( int argc, char* argv[])
{
SpecialCircle sc;
SpecialSquare ss;
// sc.push(); // can't be called - ambiguous
// ss.push();
sc.pushCircle();
ss.pushSquare();
Circle* pCircle = &sc;
pCircle->push();
Square* pSquare = &ss;
pSquare->push();
Special* pSpecial = &sc;
pSpecial->push();
pSpecial = &ss;
pSpecial->push();
return 0;
}
Rather than thinking of code reuse through inheritance, the use of mixins will give you the code reuse you want without the problems of multiple inheritance.
If you are unfamiliar with the technique, do a search on SO or Google. Make sure you search for both "mixin" and "Curiously Recurring Template Pattern". There are heaps of great articles around to get you started.
When you have to inherit from multiple interfaces with the same method the compiler can't tell which one are you trying to call, you can fix this by overriding such method and call the one you want.
class SpecialCircle : public Circle, Special {
public:
virtual void push() { Special::push(); }
};
class SpecialSquare : public Square, Special {
public:
virtual void push() { Special::push(); }
};
But in this case I think the correct OO approach is to factor out the push behavior in its own class, like Federico Ramponi have suggested.
Have a SpecialShape from Shape and SpecialCircle and SpecialSquare from SpecialShape.
Well, if the special and normal circles can be both applied forces to, and the special circle has another method that applies special forces, why not have two interfaces and two methods?
struct Applicable {
virtual ~Applicable() { }
// if it applies force, better be explicit with naming it.
virtual void applyForce() = 0;
};
struct SpecialApplicable {
virtual ~SpecialApplicable() { }
virtual void applySpecialForce() = 0;
};
struct Shape {
virtual ~Shape() { }
Size getSize();
Point getPosition();
// ...
};
struct Circle : Shape, Applicable {
virtual void applyForce() { /* ... */ }
}
struct SpecialCircle : Circle, SpecialApplicable {
virtual void applySpecialForce() { /* .... */ }
};
If it doesn't make sense if there is both a special and a normal apply method (which the name of the class - SpecialCircle - suggests), then why not do even this:
struct Circle : Shape, Applicable {
virtual void applyForce() { /* ... */ }
}
struct SpecialCircle : Circle {
// applies force, but specially
virtual void applyForce() { /* .... */ }
};
You can also put the applyForce into the Shape class. It also depends on the environment in which those classes are used. What, in any case, you really should avoid is having the same method in two base classes that appear in two difference base-lattices. Because that inevitable will lead to such ambiguity problems. The diamond inheritance is when you use virtual inheritance. I believe there are other good answers on stackoverflow explaining that. It isn't applicable for your problem, because the ambiguity arises because the method appears in two base class sub-objects of different types. (It only solves such cases where the base classes have the same type. In those cases, it will merge the base classes and there will only be one base class sub-object contained - inherited by virtual inheritance)

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.