1

我想用 C++ 实现真正的功能。特别是我想评估、区分、添加、乘以这些对象。这是我的实现

class RealFunc {
public:
    virtual int Eval(const double& x, double& result) = 0;
    virtual int Diff(const double& x, double& result) = 0;
};

class Sqrt : public RealFunc {
public:
    int Eval(const double& x, double& result);
    int Diff(const double& x, double& result); 
};

int Sqrt::Eval(const double& x, double& result) {
    if(x<0) return 0;
    else {
        result = sqrt(x);
        return 1;
    }
};

int Sqrt::Diff(const double& x, double& result) {
    if(x<=0) return 0;
    else {
        result = 0.5/sqrt(x);
        return 1;
    }
};

当我尝试添加RealFunc对象时会变得很棘手。我必须创建一个继承自的 sum 类RealFunc

RealFunc operator+(const RealFunc& f, const RealFunc& g) {
    Sum_RealFunc h(f,g);
    return h;
};

class Sum_RealFunc : public RealFunc {
public:
    Sum_RealFunc(const RealFunc& f_, const RealFunc& g_) : f(f_), g(g_) {};
    int Eval(const double& x, double& result);
    int Diff(const double& x, double& result);
private:
    RealFunc f;
    RealFunc g;
};

int Sum_RealFunc::Eval(const double& x, double& result) {
    double temp_f,temp_g;
    int success_f,success_g;
    success_f = f.Eval(x,temp_f);
    success_g = g.Eval(x,temp_g);
    result = temp_f+temp_g;
    return success_f*success_g;
};

// Same for Sum_RealFunc::Diff

我的问题是我不能使用f,因为g成员是抽象的......我应该如何继续获得一个干净的实现?Sum_RealFuncRealFunc

PS:我放的代码是我正在处理的代码的简单版本(来自 RxR->R 的函数,具有所有微分方向,如果 stepsize 成员不为零,则为有限差分以及其他辅助函数)

4

4 回答 4

3

您面临的问题是,您既需要一个与值对象(运算符重载)一起工作的特性,又需要一个只与指针一起工作的特性(继承/多态)。

作为一种解决方案,您需要一个带有重载运算符的值对象作为通过指针管理的多态对象的包装器:

class RealFuncImpl {
public:
    virtual ~RealFuncImpl(); // don't forget this for polymorphic objects

    virtual int Eval(const double& x, double& result) = 0;
    virtual int Diff(const double& x, double& result) = 0;
};

class RealFunc {
    std::shared_ptr<RealFuncImpl> impl;
public:

    int Eval(const double& x, double& result);
    int Diff(const double& x, double& result);
};

Sum_RealFuncImpl将从中派生RealFuncImpl并实现您的运算符RealFunc。您可能应该将您的类隐藏Impl在某个“详细”名称空间中,因为您的代码的最终用户不应该看到它们。

编辑:

Sum_RealFuncImpl将包含两个std::shared_ptr<RealFuncImpl>成员。

于 2012-05-29T10:15:53.030 回答
1

由于您在构造函数初始化程序列表中初始化它们,您可以使成员变量引用。

于 2012-05-29T10:14:20.617 回答
1

你有两种可能:

  • 按照 wolfgang 的建议做:仅使用共享指针的包装器。这样您就可以创建副本,而无需真正复制派生函数对象。
  • clone通过实现成员,使派生类本身可通过基类指针复制。最方便的是从 CRTP 类派生而不是直接从基类派生。我会将其设为本地课程,以免混淆:

    struct RealFunc {
      virtual std::pair<double,bool> operator()       //IMO better than this
                              (double x)const =0;    // reference-argument hackery
      virtual std::pair<double,bool> Diff
                                 (double x)const =0;
    
      virtual RealFunc* clone()const =0;
      template<class Derived>
      struct implementation : RealFunc {
        RealFunc* clone() {
          return new Derived(*static_cast<const Derived*>(this));
        }
      };
    
      virtual ~RealFunc(){}
    };
    

    现在您只需从 中派生您的函数对象implementation,以使它们可克隆:

    struct Sqrt : RealFunc::implementation<Sqrt> {
      std::pair<double,bool> operator()(double x) {
        return x>=0
                ? std::make_pair(sqrt(x), true)
                : std::make_pair(0., false);
      }
      ...
    }
    

    您的 sum 函数现在可以很好地完成std::unique_ptr

    class Sum_RealFunc : public RealFunc::implementation<Sum_RealFunc> {
      std::vector<std::unique_ptr<RealFunc>> summands;
     public:
      std::pair<double,bool> operator()(double x) {
        double result=0;
        for(auto& f: summands) {
          auto r = (*f)(x);
          if(r.second) result += r.first;
           else return std::make_pair(0., false);
        }
        return std::make_pair(result, true);
      }
    
      Sum_RealFunc(const Sum_RealFunc& cpy) {
        for(auto& f: cpy.summands)
          summands.push_back(f->clone());
      }
    
      //friend operator+=(RealFunc& acc, const RealFunc& add); //doesn't work
    };
    

    不幸的是,这不足以允许编写简单的求和表达式。我在最近的一个项目中做了一些事情,几乎解决了所有这些问题,但有点复杂:我为每个实例提供了用任何其他实例覆盖其行为的选项。像

    class RealFunc {
      std::unique_ptr<RealFunc> override;
     public:
      virtual std::pair<double,bool> operator()(double x)const {
        return (*override)(x);
      }
      virtual std::pair<double,bool> Diff(double x)const {
        return override->Diff(x);
      }
    
      auto implemented() -> RealFunc*                              {
        return implement_override? override->implemented() : this; }
      auto implemented()const -> const RealFunc*                   {
        return implement_override? override->implemented() : this; }
    
      virtual RealFunc* clone()const =0;
      template<class Derived>
      struct implementation : RealFunc {
        virtual std::pair<double,bool> operator()(double x)const =0;
        virtual std::pair<double,bool> Diff(double x)const =0;
        RealFunc* clone() {
          return new Derived(*static_cast<const Derived*>(this));
        }
      };
    
      virtual ~RealFunc(){}
    };
    

    这还不是全部,您需要override使用这种方法对所有地方进行大量检查。但最终,它可以让你非常流畅地组合功能,比如

    RealFunc f = const_realfunc(7.);
    for(auto& omega: omegas)
      f += sine_angfreq(omega);
    RealFunc g = f + noise_func(.3);
    ...
    
于 2012-05-29T10:32:13.553 回答
1

尝试

class Sum_RealFunc : public RealFunc {
    public:
        Sum_RealFunc(RealFunc& f_, RealFunc& g_) : f(f_), g(g_) {};
        int Eval(const double& x, double& result);
        int Diff(const double& x, double& result);
    private:
        RealFunc& f;
        RealFunc& g;
};

现在 f 和 g 是参考,这很好。

于 2012-05-29T10:52:40.357 回答