C++ 中的重载运算符 +

Overloading operator+ in c++

本文关键字:运算符 重载 C++      更新时间:2023-10-16

我对考试练习任务之一有一点问题。这是一段文字:

类 MyFloat 有一个私有变量浮点数。您必须编写将启用下一行代码的方法: 我的浮点数 x = 3.5; MyFloat y = x + 3.2 浮点数 z = 3.4 + y

我写了这段代码:

#include <iostream>
#include <Windows.h>
using namespace std;
class MyFloat
{
    float num;
public:
    MyFloat(float n)
    {
        num = n;
    }
    MyFloat operator+(MyFloat x)
    {
        float result;
        result = x.num + this->num;
        return result;
    }   
};
int main()
{
    MyFloat x = 3.75;
    MyFloat y = x + 3.2;
    float z = 3.4 + y;
    system("PAUSE");
}

我在这一行中得到错误:

float z = 3.4 + y;

它说:

错误 C2677:二进制"+":未找到采用类型为"MyFloat"的全局运算符(或者没有可接受的转换)

我该怎么办?如何解决这个问题???

operator+实现为非成员友元函数,MyFloat operator+(MyFloat x, MyFloat y) 2 个参数。

为什么它在当前版本中不起作用?因为成员运算符函数是在运算符左侧的对象上调用的。在左侧的情况下,您有整数文字,它不是一个对象MyFloat operator+(MyFloat x)因此缺少成员函数。

运算符的非成员变体是对称的,不需要左侧是对象。对称性很重要,因为正如您在示例中所看到的operator+它不像我们习惯于在数学中思考的那样对称


编辑:但正如卡西奥·内里在评论中指出的那样,这仍然不够。为什么?请看他的回答,但简而言之:你有歧义问题。如果你像这样手动铸造,你可以使用他的解决方案或这个解决方案:float z = 3.4f + static_cast<float>(y);这很丑陋。您可以使用其他转换:float z = MyFloat(3.4f) + y如果您提供MyFloat::operator float转换。

解决相同歧义问题的另一种解决方案:在 C++11 中,您可以使用自己的后缀文字(类似于内置浮点数的f前缀,例如 3.4_f ;(下划线表示此后缀文本是用户定义的)。示例实现(假设您实现了从MyFloatfloat和向后的转换运算符:

MyFloat operator "" _f(long double val) {
    return MyFloat(static_cast<float>(val)); }
int main() {
    MyFloat x = 3.75;
    MyFloat y = x + 3.2;
    float z = 3.4_f + y; 
}

这可能是一个解决方案:

class MyFloat
{
    float num;
public:
    MyFloat(float n)
    {
        num = n;
    }
    operator float() const {
        return num;
    }
};
int main()
{
    MyFloat x = 3.75;
    MyFloat y = x + 3.2f;
    float z = 3.4f + y;
}

最初,我也想让MyFloat operator+(MyFloat, MyFloat)成为非会员朋友功能,但它仍然没有发挥作用

float z = 3.4 + y;

进行编译。原因是3.4 + y的类型为 MyFloat,因此您无法将其分配给float z,除非您提供从 MyFloatfloat 的转换运算符。然后,3.4f + y变得模棱两可(至少对于VS 2010),因为它可以调用MyFloat operator+(MyFloat, MyFloat),也可以将y转换为float并使用内置运算符+进行float

你只有 MyFloat + float 操作,你也需要定义 float + MyFloat 操作。它们是不一样的。

将此添加到您的公共函数中:

friend float operator+ (const float& lhs, const MyFloat& rhs);

而这个课外:

float operator+ (const float& lhs, const MyFloat& rhs) {
    return lhs + rhs.num;
}

注意:根据CassioNeri的评论编辑。

虽然您可以继续定义"强制浮动"方法的答案,但我相信为了您自己的利益,您最好开始使用您的公共 API 来实现其他行为。

一般来说,简单的"强制转换"是行不通的(例如,如果MyFloat MyMatrix会发生什么?

下面的方法当然更冗长,但它强调你应该"吃自己的食物",这意味着你应该尝试基于你自己的公共接口实现额外的行为,而不是一堆晦涩的隐式强制转换或friend函数。如果您使用自己的 API:您将了解其局限性,并且如果您进行修改,可能会节省主类的重新编译。

此外,假设您要计算对类的访问次数(或以其他方式控制对基础值的访问):使用强制转换运算符,您需要在 operator float()float value() 中复制代码。

所以,这是我的拙见建议,它看起来更长,但就我的口味而言,更好地反映了OO设计原则。

#include<iostream>
class MyFloat {
 public:
  MyFloat(float value):
      m_value(value) { }
  float value() const {
    return m_value;
  }
 private:
  float m_value;
};
// Eat your own food: implement functions using your public interface
// until proven need to do otherwise. This will help you assess the
// usability of your API.
float operator+(const MyFloat& lhs, const MyFloat& rhs) { return lhs.value() + rhs.value(); }
float operator+(const MyFloat& lhs, float rhs) { return lhs.value() + rhs; }
float operator+(float lhs, const MyFloat& rhs) { return lhs + rhs.value(); }
// See, now I can define another operator without need to recompile my
// class (this could have been placed in another file)
std::ostream& operator<<(std::ostream& os, const MyFloat& mf) {
  os<<"MyFloat("<<mf.value()<<")";
  return os;
}
int main() {
  MyFloat x = 3.5;      // would not work if I had declared the constructor as "explicit"
  MyFloat y = x + 3.2;
  MyFloat z = 3.4 + y;
  std::cout<<x<<", "<<y<<", "<<z<<std::endl;
}

输出(用g++ example.cpp -Wall -Wextra编译):

MyFloat(3.5), MyFloat(6.7), MyFloat(10.1)