0

適切な数学オブジェクトを表すNatural、Rational、Complexクラスの演算を追加するのに苦労しています。xの多項式を計算するためにそれが必要です。

すべてのクラスは抽象クラスNumberを継承します。数値の配列にすべての係数があるので、多項式を計算したいと思います。そのためには、doubleを掛ける演算が必要です(xはdoubleです)。xはRationalに変換され、乗算されます。これは正常に機能します。私の問題は、抽象型Numberのクラスを追加する方法ですか?

私はそれを機能させることができません。私が得るのは、Number :: add(Number)で再帰を終了することだけではありません(Natural、Rational、Complex型のメソッドを呼び出す代わりに、それ自体を呼び出します)。

#include #include #include #include #include #include #include using namespace std;

class Natural;class Rational;class Complex;

class Number {
public:
  virtual string toString() const = 0;
  virtual Number *operator*(const Rational) const = 0;
  virtual Number *add(const Natural*) const = 0;
  virtual Number *add(const Rational*) const = 0;
  virtual Number *add(const Complex*) const = 0;
  virtual Number *add(const Number *n) const {
    n->add(this);
  }
};

class Natural : public Number {
  friend class Complex;
  int n;
public:
  Natural(const Natural &s) {
    n = s.n;
  }
  Natural(int number) : n(number) {}
  string toString() const {
    stringstream ss;
    ss << n;
    return ss.str();
  }
  operator Rational() const;
  operator Complex() const;
  operator int() const {
    return n;
  }
  Number *operator*(const Rational r) const;
  Number *add(const Natural* number) const {
    return new Natural(n + number->n);
  }
  Number *add(const Rational*) const;
  Number *add(const Complex*) const;
};

class Rational : public Number {
  friend class Natural;
  int numerator, denominator;
  void divideByGCD() {
    int a = numerator, b = denominator;
    //cout << a << ' ' << b << ' ';
    if(a < b) {
      int temp = a;
      a = b;
      b = temp;
    }
    while (b > 0) {
      int r = a % b;
      a = b; b = r;
      //cout << r << endl;
    }
    numerator /= a;
    denominator /= a;
    //cout << a << endl;
  }
public:
  Rational() {}
  Rational(const Rational &s) {
    numerator = s.numerator;
    denominator = s.denominator;
  }
  Rational(int n, int d) {
    if(d == 0) throw new runtime_error("denominator equals 0");
    if(d < 0) {
      numerator = -n;
      denominator = -d;
    } else {
      numerator = n;
      denominator = d;
    }
    divideByGCD();
  }
  Rational(double d) {
    int i = 0, mul = 1;
    int r = d-floor(d);;
    while(r!=0) {
      i++; mul *= 10;
      r = 10*r-floor(10*r);
    }
    numerator = (int)mul*d;
    denominator = mul;
    divideByGCD();
  }
  string toString() const {
    stringstream ss;
    ss << numerator;
    if(denominator > 1) ss << '/' << denominator;
    return ss.str();
  }
  operator const Complex() const;
  operator const double() const {
    return (double)numerator/denominator;
  }
  Number *operator*(const Rational r) const {
    return new Rational(numerator*r.numerator, denominator*r.denominator);
  }
  Number *add(const Rational* r) const {
    return new Rational(numerator*r->denominator+r->numerator*denominator, denominator*r->denominator);
  }
  Number *add(const Natural*) const;
  Number *add(const Complex*) const;
};

class Complex : public Number {
  friend class Rational;
  double real, imaginary;
  static const double radius = 10;
public:
  Complex() {}
  Complex(const Complex &s) {
    real = s.real;
    imaginary = s.imaginary;
  }
  Complex(const double r, const double im) : real(r), imaginary(im) {}
  string toString() const {
    stringstream ss;
    ss << real;
    if(imaginary != 0) ss << '+' << imaginary << 'i';
    return ss.str();
  }
  Number *operator*(const Rational r) const;
  Number *add(const Complex* c) const {
    return new Complex(real + c->real, imaginary + c->imaginary);
  }
  Number *add(const Natural*) const;
  Number *add(const Rational*) const;
};

Natural::operator Rational() const {
  return Rational(n,1);
}
Natural::operator Complex() const {
  return Complex(n, 0);
}
Rational::operator const Complex() const {
  return Complex((double)numerator/denominator, 0);
}

Number *Natural::operator*(const Rational r) const {
  return new Rational(n*r.numerator, r.denominator);
}
Number *Complex::operator*(const Rational r) const {
  return new Complex(real*(double)r, imaginary*(double)r);
}

Number *Natural::add(const Rational *r) const {
  if(r->denominator == 1) return new Natural(n+r->numerator);
  else return new Rational(n*r->denominator,r->denominator);
}

Number *Natural::add(const Complex *c) const {
  return c->add(this);
}

Number *Rational::add(const Natural *n) const {
  return n->add(this);
}

Number *Rational::add(const Complex *c) const {
  return new Complex(c->real+(double)*this, c->imaginary);
}

Number *Complex::add(const Natural *number) const {
  return new Complex(real+number->n, imaginary);
}

Number *Complex::add(const Rational *r) const {
  return r->add(this);
}

Number *poly(double x, Number *a[], unsigned int size) {
  if(size == 1) return a[0];
  else return a[0]->add((*poly(x, a+1, size-1))*Rational(x));
}

int main() {
  cout << (Natural(5)*(Rational)2.0)->toString() << endl;

  Number *coefs[] = {new Natural(5), new Natural(6)};
  cout <<  poly(2, coefs, 2) << endl;
}

Number :: add(Number)を修正して、Number型プログラム自体のアドオンオブジェクトを呼び出しているときに、どの仮想メソッドaddを選択するかを判断するにはどうすればよいですか?

4

3 に答える 3

0

訪問者パターンは私が探していたもののようです。関数が同じクラスで受け入れて訪問するようにしたかったのです。彼らに同じ名前を付けたのは私の間違いだったと思います。

于 2013-03-28T16:22:18.343 に答える
0

問題は次のとおりだと思います。

virtual Number *add(const Number *n) const {
   n->add(this);
}

Number * に格納されている Natural で Rational を乗算する場合、Number * を Natural * にポリモーフィックにアップキャストすることはできません。いたるところでメモリをリークしているため、ここでは参照/値がより理にかなっているという点で w/g-makulik に同意します。Number + Number のサポートを削除します。また、Natural と Rational を足すと Number * が返ってきますが、それはどのような数なのでしょうか。アーキテクチャはもう少し考える必要があると思います。基本クラスの純粋仮想メソッドを完全に取り除く可能性があります (おそらく toString を除く)。例えば:

class Number
{
    public:
        virtual string toString() = 0;
};

class Rational : public Number
{
    string toString() {...}
    // forget 'add', use operators
    Rational operator+(const Rational & _rhs) const {Rational ret; ...; return ret;}
    Rational & operator+=(const Rational & _rhs) const {...; return *this;}
    ...
}

編集 簡単に修正するには、 を取り除き、virtual Number *operator*(const Rational) const = 0;各サブクラスのバージョンに置き換えるだけでよいと思います (例: Rational * operator*(const Natural) const)

または、列挙型メンバー変数を Number に追加して、型を追跡します。

enum Type { NATURAL, RATIONAL, ...}

Type mType;

または RTTI を使用して、Number::add で適切な追加方法を選択できるようにします。

Number * add(Number * _rhs)
{
   if(_rhs->mType == RATIONAL)
      return this->add((Rational *)_rhs);
   ...
}

ちょっと雑に見えますが、うまくいきます

于 2013-03-21T19:46:04.980 に答える
0

これは、マルチディスパッチとして知られています。ここにいくつかのリンクがあります

Multiple_dispatch

マルチメソッドの最適な実装

于 2013-03-21T19:59:15.790 に答える