0

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

MyFloat 类有一个私有变量 float num。您必须编写将启用下一行代码的方法: 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”类型的全局运算符(或没有可接受的转换)

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

4

4 回答 4

6

实现operator+为具有 2 个参数的非成员朋友函数MyFloat operator+(MyFloat x, MyFloat y)

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

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


编辑:但这仍然不够,正如 Cassio Neri 在评论中指出的那样。为什么?请参阅他的答案以获取解释,但简而言之:您有歧义问题。如果您像这样进行手动铸造,您可以使用他的解决方案或这个解决方案:float z = 3.4f + static_cast<float>(y);这非常难看。您可以使用另一个演员表:float z = MyFloat(3.4f) + y如果您提供MyFloat::operator float转换。

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

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; 
}
于 2013-09-05T16:16:32.133 回答
5

这可以是一个解决方案:

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除非您提供转换运算符 from MyFloatto float。但是,然后,3.4f + y变得模棱两可(至少对于 VS 2010),因为它可以调用MyFloat operator+(MyFloat, MyFloat)或转换yfloat并使用 s 的内置运算+float

于 2013-09-05T16:27:21.397 回答
3

你只有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 的评论编辑。

于 2013-09-05T16:24:51.797 回答
0

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

一般来说,一个简单的“强制转换”不会成功(例如,如果MyFloat是,会发生什么MyMatrix?)。

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

此外,假设您想要计算对您的类的访问(或以其他方式控制对基础值的访问):使用强制转换运算符,您需要复制代码 inoperator float()和 in 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)
于 2013-09-05T19:14:41.227 回答