将常数乘以复数&运算符重载问题

时间:2009-11-17 21:18:45

标签: c++

  

复杂运算符*(double m,const   复杂的& C)                          {return c * m; }

*在上面的代码中,我试图将常数乘以复数。我收到一些错误,其中一个是[二元'运算符'有太多参数]

  

ostream&运算符<<(ostream& os,   复杂的& C)                {os<< c.real<<“,”<< c.imaginary; return os;}

*****你能告诉我在这条线路上我做错了什么。 谢谢*****

        #include <iostream>
        using namespace std;
        class Complex
        {
        private:
            double real;
            double imaginary;
        public:
            Complex();
            Complex(double r, double i = 0);
            Complex operator*(const Complex & c) const;
            Complex operator*(double mult) const; 
           Complex operator*(double m, const Complex & c)
                   { return c * m; }    
          ostream & operator<<(ostream & os, Complex & c) 
           {os << c.real <<"," << c.imaginary; return os;}

        };
        Complex::Complex()
        {
            real = imaginary = 0;
        }

        Complex::Complex(double r, double i )
        {
            real = r;
            imaginary = i;
        }
        Complex Complex::operator*(const Complex & c) const

        {
            Complex mult;
            mult.imaginary = imaginary * c.imaginary;
            mult.real = real * c.real;
            return mult;
        }

        Complex Complex::operator*(double mult) const
        {
            Complex result;
            result.real = real * mult;
            result.imaginary = imaginary * mult;
            return result;
        }
        int main()
        {
            Complex B(5, 40);
            Complex C(6, 15);
            cout << "B, and C:\n";
            cout << B << ": " << C << endl;
            cout << "B * C: " << B*C << endl;
            cout << "10 * B: " << 10*B << endl;
            return 0;
        }

3 个答案:

答案 0 :(得分:3)

这两个运营商存在问题:

class Complex {
  // ... 
  Complex operator*(double m, const Complex & c)
  {return c * m;}

  ostream & operator<<(ostream & os, Complex & c)
  {os << c.real <<"," << c.imaginary; return os;}
  // ... 
};

在其他任何事情之前:operator<<不应该改变复杂的输出,因此它应该是const。 (否则您无法输出临时对象,因为它们不能绑定到非const引用。)

由于它们是非静态成员函数,因此它们具有隐式this参数。有了它,它们有三个参数。但是,两者都是二元运算符。既然你不能让它们成为静态的(那只是因为规则这么说),你必须将它们作为自由函数来实现。但是,实施后,他们需要访问私人会员,所以你必须让他们成为你班级的朋友:

class Complex {
  // ... 
  friend Complex operator*(double m, const Complex & c);
  friend ostream & operator<<(ostream & os, const Complex & c);
  // ... 
};

Complex operator*(double m, const Complex & c)
{return c * m;}

ostream & operator<<(ostream & os, const Complex & c)
{os << c.real <<"," << c.imaginary; return os;}

在旁注中,可以在朋友声明中内联实现它们,这会使您几乎回到原始版本:

// note the friend
class Complex {
  // ... 
  friend Complex operator*(double m, const Complex & c)
  {return c * m;}

  friend ostream & operator<<(ostream & os, const Complex & c)
  {os << c.real <<"," << c.imaginary; return os;}
  // ... 
};

但是,如果您实现具体的数学类型,您的类型的用户将期望此类型的所有常见操作都可以使用它。也就是说,他们会期望c*=r能够简单地运作。所以你也需要重载operator*=。但是该运算符与operator*几乎相同,因此最好在另一个运算符之上实现一个运算符。一个常见的习惯用法是将*=(和+=等)实现为成员函数(因为它们改变了左边的参数,对于它们访问其私有数据是个好主意)和{{1作为非成员而已。 (通常这比其他方式更有效率。):

operator*

IMO是最好的解决方案。


我有。然而,还有一些事要说:

实现乘法的方式效率低下:

// note the friend
class Complex {
  // ... 
  Complex& operator*=(double rhs)
  {return /* whatever */;}

  friend ostream & operator<<(ostream & os, const Complex & c)
  {os << c.real <<"," << c.imaginary; return os;}
  // ... 
};

inline Complex operator*(Complex lhs, double rhs) // note: lhs passed per copy
{return lhs*=rhs;}

inline Complex operator*(double lhs, const Complex& rhs)
{return rhs*lhs;}

当你说 Complex Complex::operator*(const Complex & c) const { Complex mult; mult.imaginary = imaginary * c.imaginary; mult.real = real * c.real; return mult; } 时,你会调用你的类的默认构造函数,它将实部和虚部初始化为Complex mult;。接下来你要做的就是覆盖那个值。为什么不一步到位:

0

甚至更简洁

 Complex Complex::operator*(const Complex & c) const
 {
   Complex mult(real * c.real, imaginary * c.imaginary);
   return mult;
 }

当然,每次乘法只需两次。但是 - 你不希望在你的图形驱动程序的某个内循环中有这个。

此外,您的构造函数未实现The Way It Ought To be(TM)。要初始化成员数据,您应该使用初始化列表:

 Complex Complex::operator*(const Complex & c) const
 {
   return Complex(real * c.real, imaginary * c.imaginary);
 }

虽然它对Complex::Complex() : real(), imaginary() { } Complex::Complex(double r, double i) : real(r), imaginary(i) { } 这样的内置类型没有任何影响,但它也没有任何影响,并且不养成习惯是好的。使用用户定义的类型(一个有点不幸的名称,因为它适用于所有非内置函数,甚至像double这样的类型,它没有被用户定义)具有非平凡的默认构造函数,它确实有所作为:效率低得多。

原因是,当执行通过初始std::string时,C ++保证您的数据成员对象可以访问和使用。为此,必须构建它们,因为构造是将原始内存转换为对象的原因。因此,即使您没有显式调用构造函数,运行时系统仍将调用默认构造函数。如果您接下来要做的是覆盖默认构造的值,那么您再次浪费CPU周期。

最后,此构造函数{充当隐式转换运算符。也就是说,例如,如果您打算调用Complex(double r, double i = 0),但忘记包含它,但是范围内有f(real),则编译器会行使其执行一次用户定义转换的权利, call f(const complex&)变为f(4.2),并且默认调用错误的函数。这非常危险。

为了避免这种情况,你应该标记所有只能用一个参数调用的构造函数f(Complex(4.2))

explicit

答案 1 :(得分:2)

不要将Complex operator*(double m, const Complex & c)和ostream声明为成员函数(也称为方法):将它们声明为朋友函数! (如果你甚至需要他们成为朋友,如果你有明显的虚拟和真实部分的内联访问方法,你就不会这样做 - 但无论如何,重点是他们必须之外类!)。

答案 2 :(得分:0)

对于成员函数,operator*operator<<只接受一个参数,因为Complex对象已经隐含给出,即

c * r

转换为

c.operator*(r)

如果您希望使用两个参数形式,那么您正在寻找外部朋友功能。虽然Alex指出,如果您设置了reim个访问者,那么您的外部运营商就不必是朋友。