Я пишу класс, который представляет собой реализацию «математической функции».Реализация перегрузки оператора на абстрактном интерфейсе в C++
«Математическая функция качества» может быть получена из абстрактного класса: QualityFunction
. Он содержит mutable double quality
, в котором хранится скалярное значение функции после ее вычисления и метод eval
, который необходим для оценки значения функции и должен быть реализован каждым производным классом, потому что это чистый виртуальный метод.
#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;
}
};
Затем каждый производный класс от QualityFunction
должен реализовать eval
метод, потому что есть много возможных QualityFunction
s. Два примера SumSinFunction и SumCosFunction, что вычислить сумму sin
и cos
их аргумент:
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]);
}
};
Эта иерархия необходима, потому что класс Maximizer
принимает MathFunction
объекты и, неоднократно вызывая eval
найти решение как vector<double> x
, который максимизирует общее качество.
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>();
}
};
Проблема теперь, когда я хочу, чтобы создать линейные комбинации MathFunctions пути объединения производных объектов, чтобы создать новый объект, который по-прежнему является MathFunction
экземпляром с их переменными и методами, но сохраняет качество, которое является линейные комбинации качеств его компонентов. Например, я хотел бы реализовать operator+
перегружать на MathFunction
, чтобы позволить мне создать что-то вроде этого:
SumCosFunction cosfun;
SumSinFunction sinfun;
MathFunction m = cosfun + sinfun;
Один первый temptative является перегружать operator+
с помощью функции друг
friend MathFunction& operator+(const MathFunction &f1, const MathFunction &f2)
{
MathFunction *f;
// do something
}
но Я не могу, потому что конструктор MathFunction виртуальный! Итак, вопрос в том, как я могу объединить разные объекты, полученные из MathFunction, для генерации объекта, который может быть передан как MathFunction в мой класс Maximizer
? Полный код доступен на 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;
}
Не можете ли вы получить класс (например, 'ContainerFunction') из' MathFunction'? Эта 'ContainerFunction' может хранить список (например,' std :: vector') объектов 'MathFunction', которые выполняются при вызове' eval'. –
вы можете использовать идиому pimpl. 'MathFunction.pimpl -> MathFunctionImpl' и ваши математические классы наследуются от' MathFunctionImpl'. Тогда у вас не будет проблем с перегрузкой оператора. – eferion
Можете ли вы немного рассказать о том, как вы хотите использовать идиому pimpl? – linello