【问题标题】:C++ classes, implicit casting and operator overloadingC++ 类、隐式转换和运算符重载
【发布时间】:2014-08-18 16:45:43
【问题描述】:

关于我构建的类以及它如何通过 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”转换为复合体,那么一切都很好。所以我的问题是,编译器如何/为什么知道在第一行将双精度转换为复数,但(似乎)想在第二行使用双精度版本的 operator*?

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

const complex operator*(const double &other)

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

谢谢!


@MikeSeymore 有一个很好的解决方案。添加一个非成员函数。我最终得到的是:

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

世界上一切都很好。谢谢迈克。

顺便说一句:关于非类重载的讨论Operator overloading outside class

【问题讨论】:

  • 您的代码中没有收到大量针对{;} 的恼人警告吗?如果没有,请将警告级别提高一个档次。
  • 可以去掉复制赋值运算符;它所做的正是隐式生成的。
  • @KonradRudolph:实际上(现在可能不再是这种情况了)我过去使用的一些编译器如果主体中没有代码实际上会出现问题。这已成为一种可能不再需要的习惯。
  • 顺便说一句,当隐式定义做正确的事情时,您不应该定义特殊成员 - 析构函数、复制构造函数、复制和移动赋值。让编译器完成它的工作。

标签: c++


【解决方案1】:

由于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 值:这会抑制移动语义。

【讨论】:

  • operator* 不应该改变它的操作数。 *= 应该只是 *
  • @0x499602D2:它正在改变其左侧操作数的副本以获得它需要返回的值。 * 的定义不能调用 * 本身——这会导致递归死亡。
  • 好吧,我误以为lhs 是一个参考。
  • @MikeSeymour:知道了。我没有想到要创建一个非成员函数。谢谢。请注意,您提供的第一个选项对我不起作用,但最后一个选项对我有用(大多数情况下,我会发布我最终在编辑中使用的内容)。
  • @boneheadgeek,第一个是您通常如何使用包含两个 YourClasses 的复合版本来重载运算符。
猜你喜欢
  • 1970-01-01
  • 2010-12-09
  • 1970-01-01
  • 2010-10-27
  • 2013-08-25
  • 2012-02-11
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多