Adding class functionality via composition - c++

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.

Related

C++ polymorphism: how to create derived class objects

I have an abstract base class called BaseStrategy. It contains one pure virtual function calculateEfficiency(). There are two classes ConvolutionStrategy and MaxPoolStrategy which derive from this base class and implement their own specific version of calculateEfficiency().
Here is some code:
class BaseStrategy {
public:
explicit BaseStrategy();
virtual ~BaseStrategy() = default;
private:
virtual double calculateEfficiency(mlir::Operation* op) = 0;
};
class ConvolutionStrategy : public BaseStrategy {
private:
double calculateEfficiency(mlir::Operation* op)
{
//some formula for convolution
return 1;
}
};
class MaxPoolStrategy : public BaseStrategy {
private:
double calculateEfficiency(mlir::Operation* op)
{
//some formula for MaxPool
return 1;
}
};
Now I have another class called StrategyAssigner. It has method calculateAllLayerEfficiencies() whose purpose is to iterate over all layers in a network. Depending on the type of layer there is a switch statement and should call the correct calculateEfficiency() depending on the layer type.
class StrategyAssigner final {
public:
explicit StrategyAssigner(){};
public:
void calculateAllLayerEfficiencies() {
// Logic to iterate over all layers in
// a network
switch (layerType) {
case Convolution:
// Call calculateEfficiency() for Convolution
break;
case MaxPool:
// Call calculateEfficiency() for MaxPool
break;
}
};
}
int main ()
{
StrategyAssigner assigner;
assigner.calculateAllLayerEfficiencies();
}
My question is, should I store references of objects Convolution and MaxPool in the class StrategyAssigner so that I can call the respective calculateEfficiency().
Or could you suggest a better way to call calculateEfficiency(). I don't really know how to create the objects (stupid as that sounds).
I can't make calculateEfficiency() static as I need them to be virtual so that each derived class can implemented its own formula.
If you included complete code I could give a more detailed answer, but you need to store BaseStrategy pointers that are initialized with derived class instances. Here's an example made from some of your code:
std::vector<std::unique_ptr<BaseStrategy>> strategies;
strategies.emplace_back(new ConvolutionStrategy);
strategies.emplace_back(new MaxPoolStrategy);
for (int i = 0; i < strategies.size(); ++i) {
std::unique_ptr<BaseStrategy>& pStrat = strategies[i];
pStrat->calculateEfficiency(...);
}
Note that this won't compile because I don't have enough details from the code you posted to make it so, but this shows how to exploit polymorphism in the way that you need.
Also, I used smart pointers for memory management; use these at your discretion.
You can indeed use runtime polymorphism here:
Declare ~BaseStrategy virtual (you are already doing it ;-)
If you are never going to instantiate a BaseStrategy, declare one of its methods as virtual pure, e.g. calculateEfficiency (you are already doing it as well!). I would make that method const, since it doesn't look it's going to modify the instance. And it will need to be public, because it will need to be accessed from StrategyAnalyser.
Declare calculateEfficiency as virtual and override in each of the subclasses. It could also be final if you don't want subclasses to override it.
I'd keep a std::vector of smart pointers to BaseStrategy at StrategyAssigner. You can use unique_ptrs if you think this class is not going to be sharing those pointers.
The key point now is that you create heap instances of the subclasses and assign them to a pointer of the base class.
class StrategyAssigner final {
public:
void addStrategy(std::unique_ptr<BaseStrategy> s) {
strategies_.push_back(std::move(s));
}
private:
std::vector<std::unique_ptr<BaseStrategy>> strategies_{};
};
int main()
{
StrategyAssigner assigner;
assigner.addStrategy(std::make_unique<ConvolutionStrategy>());
}
Then, when you call calculateEfficiency using any of those pointers to BaseStrategy, the runtime polymorphism will kick in and it will be the method for the subclass the one that will be actually called.
class ConvolutionStrategy : public BaseStrategy {
private:
virtual double calculateEfficiency() const override {
std::cout << "ConvolutionStrategy::calculateEfficiency()\n";
return 10;
}
};
class MaxPoolStrategy : public BaseStrategy {
private:
virtual double calculateEfficiency() const override {
std::cout << "MaxPoolStrategy::calculateEfficiency()\n";
return 20;
}
};
class StrategyAssigner final {
public:
void calculateAllLayerEfficiencies() {
auto sum = std::accumulate(std::cbegin(strategies_), std::cend(strategies_), 0,
[](auto total, const auto& strategy_up) {
return total + strategy_up->calculateEfficiency(); });
std::cout << "Sum of all efficiencies: " << sum << "\n";
};
};
int main()
{
StrategyAssigner assigner;
assigner.addStrategy(std::make_unique<ConvolutionStrategy>());
assigner.addStrategy(std::make_unique<MaxPoolStrategy>());
assigner.calculateAllLayerEfficiencies();
}
// Outputs:
//
// ConvolutionStrategy::calculateEfficiency()
// MaxPoolStrategy::calculateEfficiency()
// Sum of all efficiencies: 30
[Demo]

How can I access member functions of STL classes inside derived classes that aren't in the base class? (detailed explanation in body)

Right now I have a base class, class Base{}, with two classes deriving from it, BFS{} and DFS{}. BFS has queue, and DFS has stack, so they both have a member called "nodes", but the type is their respective std::queue and std::stack. My search function takes in a pointer to base class as its parameter so that it can accept both derived classes, and runs the search by pushing and popping from the member classes inside the derived classes (as per the usual DFS BFS algorithms). The issue is, since I passed in my base class as the parameter, whenever I try to call push or pop on the member stack/queue called "nodes" from the derived classes, it always says that the push/pop cannot be done because there is no member inside the base class called "nodes". How am I supposed to make this work?
Also, this setup is a requirement of the assignment I am doing and I just can't figure out how this is supposed to work, any help is appreciated.
Thanks!
class Base {
public:
virtual void push(uint64_t roomID, float intensity, int distance) = 0;
virtual Node pop(void) = 0;
virtual int size(void) = 0;
};
class Breadth : public Base {
public:
std::queue<std::pair<uint64_t, int>> U;
void push(uint64_t roomID, float intensity, int distance) { std::pair<uint64_t, int> p(roomID, distance); U.push(p); }
Node pop() { Node rr; rr.ID = U.front().first; rr.distance = U.front().second; U.pop(); return rr; }
int size() { return U.size(); }
};
class Depth : public Base {
public:
std::stack<std::pair<uint64_t, int>> U;
void push(uint64_t roomID, float intensity, int distance) { std::pair<uint64_t, int> p(roomID, distance); U.push(p); }
UnexploredRoom pop() { U.pop(); }
int size() { U.size(); }
};
void robotSearch::searchLoop(Base* search, Discovered* D, uint64_t roomID)
{
Node room;
room.ID = roomID;
room.distance = 0;
search->U.push(room); //problem here, compiler wont let me push U
...
}
To implement custom behaviour through a pointer to a base class, you need to use virtual functions. Another approach would be to use generic code with templates.
Example:
class Base {
public:
virtual ~Base() {}
virtual void push(int i) = 0;
virtual int pop() = 0;
};
class DFS : public Base{
public:
virtual void push(int i) override { /*...*/ }
virtual int pop() override { /*...*/ return {}; }
};
class BFS : public Base {
public:
virtual void push(int i) override { /*...*/ }
virtual int pop() override { /*...*/ return {}; }
};
Right now, you have some virtual methods push and pop, but for some reason, you don't use them and instead try to access a member of the derived classes instead. You seem to have copied code from the answer by Ayjay but not applied it correctly.
That member U should really not be exposed like this, that is, it should be private, and you should use your class methods to manipulate it.
Therefore, you wouldn't write
search->U.push(room);
even if it was legal here (which it isn't, as the base class does not have anything named like that).
Instead, you go with
search->push(room);
Note that I omitted the other arguments that this takes, of course you also have to provide values for your intensity and distance arguments.
Doing so will call the appropriate method, that is either Breadth::push or Depth::push, which then will access the corresponding member of the respective class.
By the way, for reasons of control, you should use the override keyword as Ayjay did, and also, you should give a member a more descriptive name that U.

trying to grasp Decorator design for dynamic hierarchical class relationship

I'm trying to learn decorator design and I came up with something awesome, but I don't know if my idea will compile. So I created some classes:
this is the base class
class parameter
{
public:
parameter(){}
parameter(double mini, double maxi, double def) :
mini(mini),
maxi(maxi),
def(def)
{}
double mini, maxi, def;
double val;
virtual double getValue() { return val; }
virtual void setValue(double v) { val = v; }
};
This class stores smoothedParameters. smoothedParameter will add itself to the SmootherManager when they need to be smoothed and remove themselves when they are finished.
class SmootherManager
{
public:
SmootherManager() {}
juce::Array<smoothedParameter *> CurSmoothingList;
void add(smoothedParameter * sp)
{
CurSmoothingList.addIfNotAlreadyThere(sp);
}
void remove(smoothedParameter * sp)
{
CurSmoothingList.removeFirstMatchingValue(sp);
}
void doSmoothing()
{
for (auto & sp : CurSmoothingList)
sp->incValue();
}
};
This class takes values over time and outputs a smoothed value.
class smoothedParameter : public parameter
{
public:
//smoothedParameter(){}
smoothedParameter(double smoothingSpeed, SmootherManager & manager, parameter * p) :
smoothingSpeed(smoothingSpeed),
manager(manager),
p(p)
{}
double smoothingSpeed;
SmootherManager & manager;
parameter * p;
rosic::ExponentialSmoother smoother;
double getValue()
{
return smoother.getCurrentValue();
}
void setValue(double v)
{
p->setValue(v);
smoother.setTargetValue(p->getValue());
if (!smoother.finishedSmoothing())
manager.add(this);
}
void incValue()
{
smoother.getSample();
if (smoother.finishedSmoothing())
manager.remove(this);
}
};
This class takes a value and modifies it over time via a list of modifiers.
class modulatedParameter : public parameter
{
public:
modulatedParameter(parameter * p) : p(p) {}
juce::Array<modifier *> modulationInputs;
parameter * p;
double getValue()
{
double totalMod = 0;
for (const auto & m : modulationInputs)
totalMod += m->val;
return totalMod * p->getValue();
}
void setValue(double v)
{
p->setValue(v);
}
void add(modifier * sp)
{
modulationInputs.addIfNotAlreadyThere(sp);
}
void remove(modifier * sp)
{
modulationInputs.removeFirstMatchingValue(sp);
}
};
So here's how it works. You have a smoother and a modulator. If you construct a smoother inside the modulator, you get a smoothed modulator. If you construct a modulator inside a smoother, you get a non-smoothed modulator.
Here's how I wanted to use the classes:
// create the smoother manager
SmootherManager smManager;
// create modulatable parameter
auto mp = new modulatedParameter(new parameter(0.0, 1.0, 0.0));
// create a smoothable parameter
auto sp = new smoothedParameter(0.01, smManager, new parameter(0.0, 1.0, 0.0));
// create a modulatable parameter where its modifiers are smoothed
auto mp_sp = new modulatedParameter(new smoothedParameter(0.01, smManager, new parameter(0.0, 1.0, 0.0)));
// create a parameter where values are smoothed, but the modulation is not
auto sp_mp = new smoothedParameter(0.01, smManager, modulatedParameter(new parameter(0.0, 1.0, 0.0)));
ok! here's problem.
modifier myMod;
// add a modifier to sp_mp, can't do it, sp_mp has no add function.
sp_mp->add(&myMod);
I'm trying to add a modulator to the modulatedParameter of smoothedParameter. I thought of a way, but this seems wrong.
auto mp = new modulatedParameter(sp_mp->p);
mp->add(&myMod)
sp_mp = new smoothedParameter(0.01, smManager, mp));
Any time I want to add/remove a modifier, I have to go through several steps. I could think of a way to remedy this but I am just so lost as to what is a practical approach because I don't know all the possibilities of C++. The point of decorator design is that objects can have a different set of functions. ...It seems like I'd need to have an "add/remove" function for every class, defeating the purpose of this design.
The point of decorator design is that objects can have a different set
of functions.
No, the point of decorator is to get the ability of flexibly extending the object`s base functionality, while preserving its core. Usually, the word "flexibly" presumes making this extension at run-time (dynamically).
Meanwhile, C++ is statically-typed language. It means that the type of an object/variable defines, what you are allowed to do to it and what you are not. sp_mp->add(&myMod); possible IIF the type (class) of the variable sp_mp has add(...) function. This decision is made at compile-time and no design pattern can change this fact, just bare with it. C++ compiler won't let you call functions/use member variables of the variable which are not part of its type.
No matter what you do, the interface of existing type is defined statically. Wanna change it? Do it at compile-time.
Now, taking into account everything was said, we can make a logical conclusion:
If you want to add some new functions to an existing type - create a new type.
Here is a more or less classic (I believe) Decorator implementation. *I did not used shared pointers just because... OP did not use them either :)
class ICore
{
public:
virtual std::string Description() = 0;
void Describe() {
std::cout << "I am " << Description() << std::endl;
}
};
class Core final : public ICore
{
public:
std::string Description() override {
return "Core";
}
};
class IDecorator : public ICore
{
protected:
ICore* core;
public:
IDecorator(ICore* _core)
: core{ _core }
{ }
virtual ~IDecorator() {
delete core;
}
};
class Beautiful final : public IDecorator
{
public:
Beautiful(ICore* _core)
: IDecorator{ _core }
{ }
public:
std::string Description() override {
return "Beautiful " + core->Description();
}
};
class Shiny final : public IDecorator
{
public:
Shiny(ICore* _core)
: IDecorator{ _core }
{ }
public:
std::string Description() override {
return "Shiny " + core->Description();
}
};
int main()
{
ICore* core = new Core;
ICore* decorated_core = new Beautiful{ new Shiny{ core } };
core->Describe();
decorated_core->Describe();
delete decorated_core;
return 0;
}
Output:
I am Core
I am beautiful shiny Core
As you see, here Decorator did not change an interface (class prototype) - no new functions were added to the core. Also, it did not change any existing functionality. What it did, however, was the extension of the already existing behavior. It literally decorated the description of the core with 2 new word. And note - this decoration happened at runtime. If we decided to change the decoration order from new Beautiful{new Shiny{core}} to new Shiny{new Beautiful{core}} the word order would change too (from beautiful shiny Core to shiny beautiful Core).
However, if you really-really want to fulfil your primary intent - adding a brand new function with decorator... There is a way, which lets you imitate such behavior. It would look ugly in C++14 so here is a C++17 code:
class Core
{
public:
void CoreFunctional() {
std::cout << "Core functional." << std::endl;
}
};
template<typename T>
class Extend : public virtual T
{
public:
Extend() = default;
Extend(const T&) { }
public:
void ExtendedFunctional() {
std::cout << "Extended functional." << std::endl;
}
};
template<typename T>
class Utility : public virtual T
{
public:
Utility() = default;
Utility(const T&) { }
public:
void UtilityFunctional() {
std::cout << "Utility functional." << std::endl;
}
};
int main()
{
Core core;
core.CoreFunctional();
auto decorated_core = Utility{Extend{core}};
decorated_core.CoreFunctional();
decorated_core.ExtendedFunctional();
decorated_core.UtilityFunctional();
}
The output is just as you would expect, but I am not really sure, if that may be considered to be a decorator...
The point of decorator design is that objects can have a different set of functions. ...It seems like I'd need to have an "add/remove" function for every class, defeating the purpose of this design.
No. Decorator pattern, as almost all the most known patterns, is all about interfaces and thus (in C++) virtual member functions.
You define your base class (either an abstract one or a concrete one you want to use as a base) where methods that can be decorated are virtual.
A decorator decores something that exists, it neither adds nor removes functions.
Whenever you define a decorator, you end up overriding those methods to enrich them and iteratively call the base class implementation of the same method. Then you pass around pointers/references to the base class and the user doesn't know if they are decorated or not. Just call it and the right thing will happen.
Let's consider this. If you add a new method, how could you invoke it from a reference or a pointer to the base class? You cannot, so you need the actual type, that is the derived one.
This defeats the purpose of the design, not the fact that you must add a method to a base class to be able to decorate it in a derived one.
If you are looking for a pattern that lets you add or remove functions from a class, consider mixins or whatever. That's not the goal of the decorator.

Parent class referencing child variable

I have several similar classes inheriting from the same Base-Class/Interface (Base class 1), and they share a couple similar functions, but then also have their own distinct functions. They all also have their own member variables of different classes, and each of those inherits from the same Base-Class/Interface (Base class 2). Is it possible to define a variable in Base class 1, of type Base class 2, then in the actual implementation of classes using Base class 1, have the variable of type Base class 2 be its proper type. Kinda hard to explain, so simplified example below.
//Base-Class 1
class Shape
{
public Shape() {}
ShapeExtra m_var;
//The common functions
public GetVar(){ return m_var; }
}
class Circle : Shape
{
public Circle() { m_var = new CircleExtra(); }
public void CircleFunc()
{
m_var.CircleExtraFunc();
}
}
class Triangle : Shape
{
public Triangle() { m_var = new TriangleExtra(); }
public void TriangleFunc()
{
m_var.TriangleExtraFunc();
}
}
.
.
.
//Base_Class 2
class ShapeExtra
{
public ShapeExtra() {}
}
class CircleExtra : ExtraClass
{
public CircleExtra() {}
void CircleExtraFunc() {//Do stuff}
}
class TriangleExtra : ExtraClass
{
public TriangleExtra() {}
void TriangleExtra() {//Do stuff}
}
.
.
.
So, I need the m_var in the child classes to be kept it as its own unique version. Because right now (w/o the extra CircleExtra m_var;), the GetVar() works, but in CircleFunc, m_var is still type of ShapeExtra, and thus doesn't know that CircleExtraFunc exists. I could cast m_var each time I wanted to do that, but that is repetitive and not worth it in my real-world case. Is there a way to utilize the functions in unique classes based off of ShapeExtra, while keeping the GetVar() function in Shape?
Please ask questions if there is anything I left out.
Simply with inheritance and without using pointers it is not possible, as C++ is a statically-and-strictly-typed language.
You can inherit both the variable and the function, but you'll need to cast function return value.
You can also override the function to make it return the concrete type, but then you have to cast the variable inside the function.
You can also declare the same var with the concrete class in subclasses, but then you just hide the variable in the superclass and inherit nothing.
I'd rather go for a solution using templates. Make the type of the variable a template type and extend the template using a concrete type in subclasses. It'll work perfectly.
It's been a long time since I last programmed in C++ and I beg your pardon if there are errors in the following example. I'm sure you can easily make it work.
template <class S>
class Shape {
S m_var;
//......
public:
S var () {
return m_var;
}
//.......
}
class Circle: Shape <CircleExtra> {
// var method returns CircleExtra
//......
}
Edit:
Regarding some comment, to allow virtual invocation of the method, it is possible to use correlated return types. Something like the following example.
class Shape {
public:
virtual ShapeExtra *var () = 0;
}
template <typename SE>
class ConcreteShape: Shape {
public:
virtual SE *var() {
return &m_var;
}
// Constructor, etc.
private:
SE m_var;
}
Or some variation. Now concrete shapes can benefit from extending the template, as long as SE * is correlated with ShapeExtra * (the type parameter extends ShapeExtra). And you can vall the method transparently through Shape interface.
Using pointers, this is totally possible.
Using your example, you could do something like this:
#include <iostream>
#include <memory>
using namespace std;
//Extras
class ShapeExtra
{
public:
ShapeExtra() {}
void ShapeFunc() { std::cout << "Shape"; }
virtual ~ShapeExtra() = default; //Important!
};
class Shape
{
public:
std::unique_ptr<ShapeExtra> m_var;
//require a pointer on construction
//make sure to document, that Shape class takes ownership and handles deletion
Shape(ShapeExtra* p):m_var(p){}
//The common functions
ShapeExtra& GetVar(){ return *m_var; }
void ShapeFunc() {m_var->ShapeFunc();}
};
class CircleExtra : public ShapeExtra
{
public:
void CircleExtraFunc() {std::cout << "Circle";}
};
class Circle : public Shape
{
CircleExtra* m_var;
public:
Circle() : Shape(new CircleExtra()) {
m_var = static_cast<CircleExtra*>(Shape::m_var.get());
}
void CircleFunc()
{
m_var->CircleExtraFunc();
}
};
int main() {
Circle c;
//use the ShapeExtra Object
c.GetVar().ShapeFunc();
//call via forwarded function
c.ShapeFunc();
//call the circleExtra Function
c.CircleFunc();
return 0;
}
Test it on ideone
Note the use of pointers and a virtual destructor:
By using a virtual destructor in the ShapeExtra base class, you make it possible to destruct an object of any derived class, using a ShapeExtra*. This is important, because
by using a std::unique_ptr<ShapeExtra> instead of a plain C-pointer, we make sure that the object is properly deleted on destruction of Shape.
It is probably a good idea to document this behaviour, i.e. that Shape takes the ownership of the ShapeExtra*. Which especially means, that we do not delete CirleExtra* in the Circle destructor
I decided here to require the ShapeExtra* on construction, but its also possible to just use std::unique_ptr::reset() later and check for nullptr on dereferencing Shape::m_var
Construction order is this: On calling the constructor of Circle, we first create a new CircleExtra which we pass to Shape before finally the constructor of Circle is executed.
Destruction order is Circle first (was created last), then Shape which also destructs the ShapeExtra for us, including (via virtual function) the CircleExtra
I would recommend the following approach:
class ShapeExtra
{
public:
virtual ~ShapeExtra() { }
virtual void SomeCommonShapeFunc() { std::cout << "Shape"; }
};
class Shape
{
public:
virtual ShapeExtra &GetVar() = 0; // Accessor function.
};
Note that the class Shape does not have any data members at all. After that for each derived class you need:
class CircleExtra : public ShapeExtra
{
public:
void SomeCommonShapeFunc() { std::cout << "Circle"; }
};
class Circle : public Shape
{
CircleExtra m_var; // Data member with circle specific class.
public:
virtual ShapeExtra &GetVar() { return m_var; }
};
Implementation of virtual method in Circle will return reference to the base class ShapeExtra. This will allow using this extra in the base class.
Note that pointers and templates are not used at all. This simplifies the overall design.

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.