我正在编写一个实现“数学功能”的类。

可以从抽象类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,它们计算其参数的sincos的总和:
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;
};

现在,SumSinFunctionSumCosFunction需要一些更改。我添加了控制台消息来测试代码
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;
}

10-07 22:41