我正在编写一个实现“数学功能”的类。
可以从抽象类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
。两个示例是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>();
}
};
现在的问题是,当我想通过组合派生对象以创建一个新对象(其成员变量和方法仍然是
MathFunction
实例)来创建MathFunctions的线性组合时,但该对象存储的质量是其质量的线性组合组件。例如,我想在operator+
上实现MathFunction
重载,以允许我创建如下代码:SumCosFunction cosfun;
SumSinFunction sinfun;
MathFunction m = cosfun + sinfun;
第一个诱惑是通过 friend 功能重载
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;
}
最佳答案
如何实现(示例)pimpl惯用语MathFunctionImpl
将成为所有功能的基础
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;
};
我们可以使用
UnionFunciton
扩展函数之间的操作:class UnionFunction : public MathFunctionImpl
{
public:
UnionFunction( MathFunctionImpl* f1, MathFunctionImpl* f2 )
: f1(f1), f2(f2)
{ }
~UnionFunction()
{ delete f1; delete f2; }
protected:
MathFunctionImpl* f1;
MathFunctionImpl* f2;
};
现在,
SumSinFunction
和SumCosFunction
需要一些更改。我添加了控制台消息来测试代码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; }
};
现在是一个添加到函数的类:
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()); }
};
好的,我们需要创建一个存储pimpl类的类:
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;
};
就这样。主要测试代码:
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;
}