c++类,隐式强制转换和操作符重载

C++ classes, implicit casting and operator overloading

本文关键字:转换 操作符 重载 c++      更新时间:2023-10-16

我遇到了一些我不理解的东西,关于我构建的类,以及它如何通过c++中的操作符重载与内置类型交互。下面是一个(不完全)复数类的例子:

class complex {
public:
  complex(double real=0., double imag=0.) : _real(real), _imag(imag) {;}
  ~complex() {;}
  complex& operator=(const complex &rhs) {
    if(this!=&rhs) {
      this->_real = rhs._real;
      this->_imag = rhs._imag;
    }
    return *this; 
  }
  complex& operator*=(const complex &rhs) {
    this->_real = this->_real * rhs._real + this->_imag * rhs._imag;
    this->_imag = this->_real * rhs._imag + this->_imag * rhs._real;
    return *this;
  }
  const complex operator*(const complex &other) const {
    complex result = *this;
    result *= other;
    return result;
  }
protected:
  double _real;
  double _imag;
};

当我用下面的main调用这段代码时:

int main(void)
{
  complex a(1.,0.);
  complex b;
  b = a * 2.;
  b = 2. * a;
  return 0;
}

我得到"main.cpp"中倒数第二行的编译器错误:

错误:在' 2.0e+0 * a '中没有匹配' operator* '

但前一行没有错误。如果我将违规行中的"2.0"转换为复合体,那么一切都很好。所以我的问题是,编译器如何/为什么知道在第一行将双精度转换为复数,但(似乎)想要在第二行使用操作符*的双精度版本?

如果我可以派生出一个类,比如Real,它派生自double并添加如下内容

const complex operator*(const double &other)

那么我认为这将工作,但我知道我不能这样做(内置类型不能用作基类)。

谢谢!


@MikeSeymore有一个很好的修复。添加一个非成员函数。我最后写的是:

complex operator*(double lhs, complex const &rhs) {
  complex result(lhs,0.);
  return result*=rhs;
}

和一切都是美好的世界。谢谢迈克。

关于非类重载操作符在类
之外重载的讨论

由于operator*是成员函数,因此只能对其右操作数进行转换。左操作数必须为complex类型。

最简单的修复方法是使其成为非成员:

complex operator*(complex lhs, complex const & rhs) {return lhs *= rhs;}

如果性能很重要,那么您可能希望为double提供专门化,而不是依赖于隐式转换,以避免不必要的零乘法:

// This one can be a member or a friend, according to taste
complex operator*(double rhs) const {return complex(_real * rhs, _imag * rhs);}
// This one can't be a member
complex operator*(double lhs, complex const & rhs) {return rhs * lhs;}

一般情况下,您不应该返回const值:这会抑制移动语义。