I'm writing a class that is an implementation of a "mathematical function".
The "mathematical quality function" can be derived from an abstract class: QualityFunction
. It contains a mutable double quality
that stores the scalar value of the function once evaluated, and an eval
method that is needed to evaluate the function value and has to be implemented by every derived class, because is a pure virtual method.
#include <vector>
#include <iostream>
#include <cmath>
using std::cout;
using std::cerr;
using std::endl;
using std::sin;
using std::cos;
using std::vector;
class MathFunction
{
protected:
mutable double quality; // mutable keyword allows to modify quality even in const methods.
virtual void eval(const vector<double> &x) const = 0;
public:
virtual ~MathFunction() {}
double &operator()()
{
return quality;
}
double &operator()(const vector<double> &x) const
{
eval(x);
return quality;
}
};
Then every derived class from QualityFunction
has to implement the eval
methods, because there are many possible QualityFunction
s. Two examples are SumSinFunction and SumCosFunction that compute the sum of sin
and cos
of their argument:
class SumSinFunction : public MathFunction
{
public:
SumSinFunction(){};
~SumSinFunction() {};
protected:
void eval(const vector<double> &x) const
{
quality = 0;
for (size_t i=0; i<x.size(); ++i)
quality += sin(x[i]);
}
};
class SumCosFunction : public MathFunction
{
public:
SumCosFunction(){};
~SumCosFunction() {};
protected:
void eval(const vector<double> &x) const
{
quality = 0;
for (size_t i=0; i<x.size(); ++i)
quality += cos(x[i]);
}
};
This hierarchy is needed because a class Maximizer
accepts MathFunction
objects and, repeatedly calling eval
will find the solution as a vector<double> x
that maximizes the overall quality.
class Maximizer
{
public:
Maximizer(){}
vector<double> maximize(const MathFunction &f)
{
// do some operations to maximize it
// and return the maximized value
return std::vector<double>();
}
};
The problem now is when I want to create linear combinations of MathFunctions by combining derived objects to create a new object that still is a MathFunction
instance with their member variables and methods, but that stores a quality that is a linear combinations of the qualities of its components. For example, I would like to implement the operator+
overloading on MathFunction
to allow me to create something like this:
SumCosFunction cosfun;
SumSinFunction sinfun;
MathFunction m = cosfun + sinfun;
One first temptative is to overload the operator+
by means of friend function
friend MathFunction& operator+(const MathFunction &f1, const MathFunction &f2)
{
MathFunction *f;
// do something
}
but I can't because the constructor of MathFunction is virtual! So the question is, how can I combine different objects derived from MathFunction to generate an object that can be passed as MathFunction to my Maximizer
class?
The full code is available on coliru http://coliru.stacked-crooked.com/a/3c33664066a3658b
int main()
{
vector<double> x;
for (int i=0; i<10;i++)
x.push_back(i);
SumCosFunction cosfun;
SumSinFunction sinfun;
//MathFunction F;// = cosfun+sinfun;
Maximizer opt;
opt.maximize(cosfun);
return 0;
}
How to implement (an example) pimpl idiom
MathFunctionImpl
will be the base of all functions
class MathFunctionImpl
{
protected:
mutable double quality; // mutable keyword allows to modify quality even in const methods.
virtual void eval(const vector<double> &x) const = 0;
public:
virtual ~MathFunctionImpl() {}
double &operator()()
{ return quality; }
double &operator()(const vector<double> &x) const
{
eval(x);
return quality;
}
virtual MathFunctionImpl* Clone() const = 0;
};
We can use UnionFunciton
to expand operations between functions:
class UnionFunction : public MathFunctionImpl
{
public:
UnionFunction( MathFunctionImpl* f1, MathFunctionImpl* f2 )
: f1(f1), f2(f2)
{ }
~UnionFunction()
{ delete f1; delete f2; }
protected:
MathFunctionImpl* f1;
MathFunctionImpl* f2;
};
Now, SumSinFunction
and SumCosFunction
needs a few changes. I added console messages to test the code
class SumSinFunction : public MathFunctionImpl
{
public:
SumSinFunction(){}
~SumSinFunction() {}
protected:
void eval(const vector<double> &x) const
{
quality = 0;
for (size_t i=0; i<x.size(); ++i)
{
if( i>0) std::cout << "+";
std::cout << "sin(" << x[i] << ")";
quality += sin(x[i]);
}
}
MathFunctionImpl* Clone() const
{ return new SumSinFunction; }
};
class SumCosFunction : public MathFunctionImpl
{
public:
SumCosFunction(){}
~SumCosFunction(){}
protected:
void eval(const vector<double> &x) const
{
quality = 0;
for (size_t i=0; i<x.size(); ++i)
{
if( i>0) std::cout << "+";
std::cout << "cos(" << x[i] << ")";
quality += cos(x[i]);
}
}
MathFunctionImpl* Clone() const
{ return new SumCosFunction; }
};
And now a class to Add to functions:
class SumFunctions : public UnionFunction
{
public:
SumFunctions(MathFunctionImpl* f1, MathFunctionImpl* f2 )
: UnionFunction(f1,f2)
{ }
~SumFunctions()
{ }
void eval(const vector<double> &x) const
{
std::cout << "(";
quality = (*f1)(x);
std::cout << "+";
quality += (*f2)(x);
std::cout << ")";
}
MathFunctionImpl* Clone() const
{ return new SumFunctions(f1->Clone(),f2->Clone()); }
};
Ok, we need to create a class that stores our pimpl classes:
class MathFunction
{
public:
MathFunction( MathFunctionImpl* impl )
: impl(impl)
{ }
~MathFunction()
{ delete impl; }
double &operator()()
{
return (*impl)();
}
double &operator()(const vector<double> &x) const
{
return (*impl)(x);
}
// This method can be friend
MathFunction operator+(const MathFunction& f2) const
{
return MathFunction(new SumFunctions(impl->Clone(), f2.impl->Clone()));
}
private:
MathFunctionImpl* impl;
};
And that's all. The main to test the code:
int main()
{
vector<double> x;
for (int i=0; i<10;i++)
x.push_back(i);
MathFunction f1( new SumCosFunction );
MathFunction f2( new SumSinFunction );
MathFunction sum = f1 + f2;
double value = sum(x);
std::cout << "=" << value << std::endl;
return 0;
}