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

Time:09-20

as a part of my uni task I need to write class for rational numbers, override math operator, compare operators, etc. But I also need to overload cast to short, int and long types. Here is simplified code for my class:

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;
  }
  //...
};

The problem is, if I now want to multiply RationalNumber object by int, I'll get an error saying this operation is ambiguous:

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;
}

Adding constructor specifically for single int -- dosen't work. The thing that Does work -- adding RationalNumber::operator*(int). Problem with this approach is: I need to override ALL math operations, compare operations, etc, for int since I have cast operator to int -- operator int.

Ok, but even if I'll do that, the second I try to use unsigned compiler will bombard me with tons of warnings about casting unsigned to int and potential data loss (thought it will compile):

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;
      | 

To completely satisfy compiler I need to add RationalNumber::operator*(unsigned). Now let's remember that I need to overload 3 casting operators and a dozen of math/compare operators. Which means I need to create 6 extra functions for EACH operator overload.

So, can I somehow force compiler to always cast values in favor of my class?

CodePudding user response:

Implicit conversions can cause problems and can have a negative effect on readability. If possible make the conversions explicit and keep implicit conversions for exceptional cases, when you are sure that an implicit conversion is appropriate. The call is no longer ambiguous if you make the conversion explicit:

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

Live Demo

It is one of the many cases where C s defaults are a little odd. Conversions should be explicit by default and only in special cases they can be implicit.

  • Related