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ます。から継承する合計クラスを作成する必要があります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

ここでの私の問題は、抽象的であるためfgメンバーとして使用できないことです...クリーンな実装を取得するにはどうすればよいですか?Sum_RealFuncRealFunc

PS:私が置いたコードは、私が取り組んでいるものの軽量バージョンです(すべての微分方向を持つRxR-> Rからの関数、ステップサイズメンバーがゼロでない場合の有限差分、および他のサイド関数)

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し、の演算子を実装しますRealFuncImplコードのエンドユーザーにはクラスが表示されないため、クラスを「詳細」名前空間に隠す必要があります。

編集:

あなたSum_RealFuncImplには2人のstd::shared_ptr<RealFuncImpl>メンバーが含まれます。

于 2012-05-29T10:15:53.030 に答える
1

コンストラクタ初期化子リストで初期化するので、メンバー変数を参照することができます。

于 2012-05-29T10:14:20.617 に答える
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 に答える
1

次の 2 つの可能性があります。

  • 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);
      }
      ...
    }
    

    合計関数は、次のようにうまく実行できるようになりました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 に答える