为数学函数C ++实现乘法运算符

时间:2015-02-23 18:49:09

标签: c++ operator-overloading

我有以下抽象基类:

class Function {
 virtual double Eval(double x) const = 0;
};     

我希望能够使用像f * g或f-> operator *(g)这样的表达式,其中f和g是我的主文件中类Function的具体对象,例如当我想要时计算一个定积分,以便我可以写:

AnIntegrationMethod(f*g);

我提出的一个相当简单的方法包括声明一个类Product(只显示头文件,实现很明显):

class Product: public Function {
 public: Product(Function *g, Function *f); 
  ~Product(); 
  virtual double Eval(double x) const; //return _g->Eval(x)*_f->Eval(x)
 private: Function *_g; Function *_f;
 };

然后在我的任何功能中

#include "Product.h"

class ConcreteFunction: public Function {
 public: 
   ConcreteFunction(); 
  ~ConcreteFunction(); 
  virtual double Eval(double x) const;
 Function* operator*(Function *f) {return new Product(this, f);}
 };

这实际上适用于简单的东西,但问题是operator *仅在基类的单个派生类中定义,而不是为每个可能的派生类定义。这意味着,例如,如果我有一个表示数学函数的具体对象f,我可以调用f-> operator * g但是如果我想再次调用operator *来获取对象(f-> operator * g ) - > operator * f我无法做到,因为函数f * g没有将*运算符定义为f。

我想我应该直接在我的基类中定义operator *,但是我无法弄清楚如何实现运算符,因为我真的不知道如何为产品获得正确的Eval函数因为我现在不能使用Product类,所以在类Function函数本身中使用从类Function派生的Product类是没有意义的。我想我也很困惑一般是否正确写下面的内容:

 Function* Function::operator*(Function *f) {
 Function *g;
 ...
 //operations that allow g to be have the right Eval function
 //which should of the sort this->Eval(x) * f->Eval(x)
 ...
 return g;
 }

任何关于如何进行的提示或建议都表示赞赏。我的水平很基础,我现在已经编程了两个月。

3 个答案:

答案 0 :(得分:2)

您可以将operator*重载为独立功能。即使它不是Product.h/cpp的成员,也要将它放在Product中,因为它与它紧密相关。

Product.h

Function* operator*(Function *f, Function *g);

Product.cpp

Function* operator*(Function *f, Function *g) {
    return new Product(f, g);
}

与加法,减法等相同

或者,您可以将它们实现为成员函数,但将定义放在Function.cpp中并在其中包含Product.h等。

注意您的设计存在巨大缺陷。您在堆上创建new个函数对象并传递指针。你需要在代码中的某个地方delete,我假设在你的解构器中。但是你还需要take care about copying your objects。通常,手动关注正确删除是一场噩梦,并且有自动方法(称为&#34;内存管理&#34;)。例如,您可以考虑使用智能指针。看看std::shared_ptr。虽然在每种情况下都不是最有效的,但是当你第一次想要学习语言而不是太多关于内存管理的细节时,通常使用它是一件好事。要将shared_ptr应用于您的代码,请将每个Function*替换为shared_ptr<Function>,并将new Function(...)替换为make_shared<Function>(...)(与其他类型相同)。

另请注意*数学函数含糊不清:在某些上下文/文献中,f*g表示将结果乘以,而在其他情境中它意味着功能卷积

答案 1 :(得分:2)

只是草图,您可能会这样做:

#include <memory>

// Base Function: f(x) = x
class Function
{
    protected:
    struct Implementation
    {
        virtual ~Implementation() {}
        virtual double evaluate(double x) const { return x; }
    };

    public:
    Function()
    :   self(std::make_shared<Implementation>())
    {}

    double operator () (double x) const { return self->evaluate(x); }

    protected:
    Function(std::shared_ptr<Implementation> self)
    :   self(self)
    {}

    private:
    std::shared_ptr<Implementation> self;
};
typedef Function Identity;


// Unary Function: u(-f(x))
class UnaryMinus : public Function
{
    protected:
    struct Implementation : Function::Implementation
    {
        Function f;
        Implementation(Function f)
        :   f(f)
        {};

        virtual double evaluate(double x) const override { return -f(x); }
    };

    public:
    UnaryMinus(Function f)
    :   Function(std::make_shared<Implementation>(f))
    {}
};

// Binary Function: u(f(x) + g(x))
class BinaryAdd : public Function
{
    protected:
    struct Implementation : Function::Implementation
    {
        Function f;
        Function g;
        Implementation(Function f, Function g)
        :   f(f), g(g)
        {};

        virtual double evaluate(double x) const override { return f(x) + g(x); }
    };

    public:
    BinaryAdd(Function f, Function g)
    :   Function(std::make_shared<Implementation>(f, g))
    {}
};

// Binary Function: u(f(x) * g(x))
class BinaryMultiply : public Function
{
    protected:
    struct Implementation : Function::Implementation
    {
        Function f;
        Function g;
        Implementation(Function f, Function g)
        :   f(f), g(g)
        {};

        virtual double evaluate(double x) const override { return f(x) * g(x); }
    };

    public:
    BinaryMultiply(Function f, Function g)
    :   Function(std::make_shared<Implementation>(f, g))
    {}
};

inline UnaryMinus operator - (Function f) { return UnaryMinus(f); }
inline BinaryAdd operator + (Function f, Function g) { return BinaryAdd(f, g); }
inline BinaryMultiply operator * (Function f, Function g) { return BinaryMultiply(f, g); }

#include <iostream>
int main() {
    Identity x;
    Function result = -x * (x + x) + x;
    std::cout << result(2) << '\n';
}

答案 2 :(得分:1)

这是一个C ++ 11通用编程解决方案,它不依赖于继承的多态(即 - 虚函数),也不需要动态分配。

我不是C ++专家,这可能会在很大程度上得到改善,但它可以起作用并获得理念。特别是,下面的代码仅适用于double的函数。您可以将操作数和返回类型设置为模板类型,这样一般可以在不同类型(例如 - 复杂)上工作。我不知道对模板运算符进行范围调整的正确方法,以便您可以使用简写运算符表示法,而不是意外调用(或使其不明确)具有operator()(double x)的其他类型。如果有人有任何改进这个答案的建议,那么请加入,我会编辑我的答案。

#include <iostream>

using namespace std;

struct Identity
{
  double operator() (double x) const { return x; }
};

struct Constant
{
  template<typename T1>
  Constant(const T1 &x) : _x(x) {}

  double operator()(double x) const { return _x; }

private:
  double _x;
};


template<typename T1>
struct Negate
{
  Negate(const T1 &f) : _f(f) {}

  double operator() (double x) const { return -_f(x); }

private:
  T1 _f;
};

template<typename T1>
struct Reciprocal
{
  Reciprocal(const T1 &f) : _f(f) {}

  double operator() (double x) const { return 1 / _f(x); }

private:
  T1 _f;
};

template<typename T1, typename T2>
struct Sum
{
  Sum(const T1 &f, const T2 &g) : _f(f), _g(g) {}

  double operator() (double x) const { return _f(x) + _g(x); }

private:
  T1 _f;
  T2 _g;
};

template<typename T1, typename T2>
struct Product
{
  Product(const T1 &f, const T2 &g) : _f(f), _g(g) {}

  double operator() (double x) const { return _f(x) * _g(x); }

private:
  T1 _f;
  T2 _g;
};

template<typename T1> 
Negate<T1> operator-(const T1 &f) 
{ return Negate<T1>(f); }

template<typename T1, typename T2> 
Sum<T1, T2> operator+(const T1 &f, const T2 &g) 
{ return Sum<T1, T2>(f, g); }

template<typename T1, typename T2> 
Sum<T1, Negate<T2> > operator-(const T1 &f, const T2 &g) 
{ return Sum<T1, Negate<T2> >(f, Negate<T2>(g)); }

template<typename T1, typename T2> 
Product<T1, T2> operator*(const T1 &f, const T2 &g) 
{ return Product<T1, T2>(f, g); }

template<typename T1, typename T2> 
Product<T1, Reciprocal<T2> > operator/(const T1 &f, const T2 &g) 
{ return Product<T1, Reciprocal<T2> >(f, Reciprocal<T2>(g)); }


int main()
{
  auto f = (Identity() * Constant(4.0) + Constant(5)) / Identity();  // f(x) = (x * 4 + 5) / x; f(2) = 6.5
  auto g = f * f;                                                    // g(x) = f(x) * f(x);     g(2) = 42.25

  cout << f(2) << " " << g(2) << " " << (g / f)(2) << endl;  // prints 6.5 42.25 6.5

  return 0;
}

编辑:这种方法的主要缺点是“公式”的类型必须在编译时完全已知并嵌入模板生成的类中。这意味着非常复杂的公式将生成许多不同的类和代码。因此,这种方法可能会导致令人讨厌的代码膨胀。此外,你不能做类似的事情:

for (i = 1; i < j; ++i)  // raise f to the jth power (other than 0)
  f *= f;  

由于f的类型必须在编译时完全已知,并且乘法迭代地调用新类型。使用类层次结构,动态分配(使用自动清理)和多态的其他方法可以做到这一点,并且没有代码膨胀的问题。尽管如此,尝试还是很有趣。