【问题标题】:Odd behavior with operator>= overloadingoperator>= 重载的奇怪行为
【发布时间】:2010-10-07 17:23:23
【问题描述】:

我在 C++ 中使用运算符重载时出现了奇怪的行为。我有一堂课,我需要检查它的内容是否大于或等于 long double。我重载了 >= 运算符来做这个检查,我的声明如下:

bool MyClass::operator>=(long double value) const;

我不得不说,我的班级还有一个 cast-to-long-double 运算符,它仅在某些条件下无例外地工作。 现在,当我使用此运算符时,编译器会抱怨 operator>= 的使用不明确,而替代方法是:

  • 我的。
  • 内置operator>=(long double, int)

现在,我如何强制程序使用我的操作符?

【问题讨论】:

    标签: c++ operator-overloading overload-resolution


    【解决方案1】:

    2015 年更新: 或者,如果您想使用 (double)obj 语法而不是 obj.to_double() 语法来保持转换能力,请在转换函数 explicit 前加上该关键字作为前缀。然后您需要显式转换才能触发转换。就个人而言,我更喜欢.to_double 语法,除非转换为bool,因为在这种情况下,if(obj) 使用转换,即使它是explicit,这比if(obj.to_bool()) 更具可读性我的意见。


    删除转换运算符。一路上都会惹来麻烦。有这样的功能

    to_double()
    

    或类似的返回双精度值并显式调用该函数以获得双精度值。

    对于手头的问题,有这个问题:

    obj >= 10
    

    考虑这个表达式。内置运算符使用转换运算符 long double() 通过用户定义的类型转换序列匹配第一个参数。但是您的函数通过从 int 到 long double (整数到浮点转换)的标准转换序列匹配第二个参数。当有两个参数的转换时总是模棱两可的,但至少有一个参数可以转换得更好,而其余的参数在一次调用中不会转换得更糟。在您的情况下,内置函数更好地匹配第二个参数,但第一个更差,但您的函数更好地匹配第一个参数,但第二个更差。

    这很令人困惑,所以这里有一些例子(从 char 到 int 的转换称为提升,这比从 char 到非 int 的转换更好,称为转换):

    void f(int, int);
    void f(long, long);
    f('a', 'a');
    

    调用第一个版本。因为第一个参数的所有参数都可以更好地转换。同样,以下仍将调用第一个:

    void f(int, long);
    void f(long, long);
    f('a', 'a');
    

    因为第一个可以转换得更好,而第二个不能转换得更差。但以下是模棱两可的

    void f(char, long);
    void f(int, char);
    f('a', 'a'); // ambiguous
    

    在这种情况下更有趣。第一个版本通过完全匹配接受第一个参数。第二个版本通过完全匹配接受第二个参数。但是两个版本至少同样好地不接受他们的另一个论点。第一个版本需要对其第二个参数进行转换,而第二个版本需要对其参数进行提升。因此,即使促销比转换更好,对第二个版本的调用也会失败。

    这与您上面的情况非常相似。即使标准转换序列(从 int/float/double 转换为 long double)更好 比用户定义的转换序列(从 MyClass 转换为 long double),您的运算符版本未被选择,因为您的其他参数(long double)需要从参数进行转换,这比内置运算符对该参数所需的更差(完美匹配)。

    重载解析在 C++ 中是一件复杂的事情,因此人们不可能记住其中的所有微妙规则。但是得到粗略的计划是很有可能的。希望对你有帮助。

    【讨论】:

      【解决方案2】:

      通过提供到 double 的隐式转换,您实际上是在声明,我的类相当于 double,因此您不应该真正介意 doubles 的内置运算符 >= 是否为用过的。如果您确实在乎,那么您的课程实际上并不“等同于”double,您应该考虑不提供到double隐式转换,而是提供 显式 GetAsDouble 或 ConvertToDouble 成员函数。

      您目前有歧义的原因是,对于表达式t >= d,其中t 是您的类的实例,d 是双精度,编译器始终必须提供左手侧或右手侧所以表达真的是模棱两可的。要么调用 toperator double 并使用 doubles 的内置运算符 >=,要么必须将 d 提升为 long double 并使用您的成员运算符 >=。

      编辑,您已经更新了您的问题,表明您的转换是 long double 并且您的比较是针对 int 的。在这种情况下,最后一段应为:

      您目前有歧义的原因是,对于表达式t >= d,其中t 是您的类的实例,dint,编译器总是必须提供无论是左侧还是右侧,所以表达确实是模棱两可的。要么调用toperator long double,并使用long doubleint 的内置运算符>=,或者必须将d 提升为long double,并且使用您的成员运算符>=。

      【讨论】:

        【解决方案3】:

        我假设您正在与文字 int 进行比较,而不是 long double

        MyClass o;
        
        if (o >= 42)
        {
           // ...
        }
        

        如果是这种情况,两种选择都一样好/复杂。

        使用您的operator long double()

        1. MyClass::operator long double()
        2. 内置operator>=(long double, int)

        使用您的MyClass::operator>=(long double)

        1. 内置转换intlong double
        2. MyClass::operator>=(long double)

        【讨论】:

        • 我实际上是在与一个 long double 进行比较。
        【解决方案4】:

        您的声明中有long double。尝试将其更改为double

        【讨论】:

        • 抱歉,我的意思是到处都是 long double。
        【解决方案5】:

        您将运算符重载与自定义转换结合使用可能会让您的类的用户非常困惑。问问自己,这个类的用户会期望它将自己转换成双精度数,还是可以与双精度数相媲美? .greaterThan(double) 函数不会达到相同的目标,但不会让用户感到惊讶吗?

        我想你总是可以在比较之前明确地将你的对象转换为 double,以避免模棱两可。但如果我是你,我会重新考虑上面的方法,并专注于编写直观且行为方式并不令人惊讶的代码,而不是花哨的类型转换和运算符重载。

        (灵感来自 FQA 的精彩 rant about operator overloading

        【讨论】:

          【解决方案6】:
          • 内置运算符>=(long double, int)。

          看起来你已经定义了:

          bool class::operator>=(long double value) { return value >= classValue; }
          

          而你不见了:

          bool class::operator>=(double value)      { return value >= classValue; }
          bool class::operator>=(int value)         { return value >= classValue; }
          

          因此编译器无法决定转换哪种方式。 (这是模棱两可的。)

          也许模板化的函数(或方法)会有所帮助?

          注意 a>=b 调用与 b>=a 不同的方法的情况。

          【讨论】:

            猜你喜欢
            • 2020-08-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-01-25
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多