类数学操作重载,适用于也具有强制转换运算符重载的类型

class math operation overload for types which are also have cast operator overloaded

提问人:John 提问时间:9/20/2022 更新时间:9/20/2022 访问量:80

问:

作为我的 uni 任务的一部分,我需要为有理数编写类、覆盖数学运算符、比较运算符等。但我还需要将强制转换为 和 类型。这是我的类的简化代码:shortintlong

class RationalNumber {
  long long numerator, divider;
public:
  RationalNumber() : numerator(0), divider(1) {}
  RationalNumber(long long numerator, long long divider = 1) : numerator(numerator), divider(divider) {}
  
  // Let's take only one math operator
  RationalNumber operator*(const RationalNumber& other) {
    return { numerator * other.numerator, divider * other.divider };
  }

  // And one cast operator
  operator int() {
    return numerator / divider;
  }
  //...
};

问题是,如果我现在想将 RationalNumber 对象乘以 ,我会收到一个错误,说这个操作不明确:int

int main() {
  int integer = 2;
  RationalNumber rational(1, 2);
  
  rational * integer;
  // Well, ambiguous:
  // 1. Cast 'rational' to int and multiply. Or
  // 2. Cast 'integer' to RationalNumber and RationalNumber::operator*
  return 0;
}

添加专门用于单个的构造函数 -- 不起作用。确实有效的东西 -- 添加 .这种方法的问题是:我需要覆盖所有数学运算、比较运算等,因为我已将运算符转换为 int -- .intRationalNumber::operator*(int)intoperator int

好的,但即使我会这样做,我尝试使用编译器的第二个也会用大量关于转换和潜在数据丢失的警告轰炸我(认为它会编译):unsignedunsignedint

class RationalNumber {
  //...
public:
  //...
  RationalNumber operator*(int othNum) {
    return { numerator * othNum, divider };
  }
  //...
};

int main() {
  unsigned int uinteger = 2;
  RationalNumber rational(1, 2);

  rational * uinteger; // Well... AAAAAAA
  return 0;
}
test.cpp: In function ‘int main()’:
test.cpp:29:14: warning: ISO C++ says that these are ambiguous, even though the worst conversion for the first is better than the worst conversion for the second:
   29 |   rational * integer;
      |              ^~~~~~~
test.cpp:14:18: note: candidate 1: ‘RationalNumber RationalNumber::operator*(int)’
   14 |   RationalNumber operator*(int othNum) {
      |                  ^~~~~~~~
test.cpp:29:14: note: candidate 2: ‘operator*(int, unsigned int)’ (built-in)
   29 |   rational * integer;
      | 

为了完全满足编译器的要求,我需要添加.现在让我们记住,我需要重载 3 个转换运算符和十几个数学/比较运算符。这意味着我需要为 EACH 运算符重载创建 6 个额外的函数。RationalNumber::operator*(unsigned)

那么,我可以以某种方式强制编译器始终为我的类转换值吗?

C++ Casting 重载

评论


答:

5赞 463035818_is_not_an_ai 9/20/2022 #1

隐式转换可能会导致问题,并可能对可读性产生负面影响。如果可能,请显式转换,并在确定隐式转换适合的情况下保留隐式转换以备不时之需。如果您进行转换,则调用不再模棱两可:explicit

explicit operator int() {
  return numerator / divider;
}

现场演示

这是 C++ 默认值有点奇怪的众多情况之一。默认情况下,转换应该是显式的,只有在特殊情况下,它们才能是隐式的。

评论

0赞 Eljay 9/20/2022
让我想起了Kate Gregory关于C++的出色(像往常一样!)的演讲,她讨论了“所有的默认值都是错误的”。
1赞 463035818_is_not_an_ai 9/20/2022
@Eljay我是从某个地方得到的,只是不记得;)不过,如果你看一下较新的东西,很明显时代已经发生了变化,例如使用 lambda 表达式,您可以制作它们,而不是必须制作它们。mutableconst