Say I have a very simple Rational class like the one below:
class Rational
{
int numer;
int denom;
public:
Rational(const int& numer, const int& denom) : numer(numer), denom(denom) {}
void operator*(const Rational& other) { std::cout << "multiply, simple as\n"; }
}
All well and good. Then say that I want to be able to multiply my Rational class with an integer, so I add another function to the class:
class Rational
{
int numer;
int denom;
public:
Rational(const int& numer, const int& denom) : numer(numer), denom(denom) {}
void operator*(const Rational& other) { std::cout << "multiply, simple as\n"; }
void operator*(const int& other) { std::cout << "some math here\n"; }
}
Ok no big deal. Except that I can't actually do the following because the order of the parameters would be all wrong:
Rational mine(1, 2);
const Rational result = 2 * mine;
Ok, one more iteration and I have the following:
class Rational
{
int numer;
int denom;
public:
Rational(const int& numer, const int& denom) : numer(numer), denom(denom) {}
void operator*(const Rational& other) { std::cout << "multiply, simple as\n"; }
void operator*(const int& other) { std::cout << "some math here\n"; }
friend void operator*(const int& other, const Rational& mine) { std::cout << "even more math here\n"; }
}
What I'm trying to find out is if there's a way that I can avoid having to write the same function twice for every mathematical operation that I'd want my class to support, just so that I can call it with the arguments in whatever order I want. This may well just be how you have to implement this sort of thing within C 's type system, but it seems a tad annoying to have to add this boilerplate for every mathematical operation that you want your class to support.
CodePudding user response:
The issue with having a single function is that the type of the left and right operands to *
would vary (and you would have to use them differently).
This can be solved by fixing both of the argument types to Rational
and creating an implicit conversion from an int
x
to Rational
x/1
(which is probably desirable anyways). This way, in 2 * mine
, the 2
will implicitly be converted to Rational(2, 1) * mine
.
Here's an example:
class Rational
{
int numer;
int denom;
public:
// default argument of denom=1 allows implicit conversion from int
Rational(int numer, int denom = 1) : numer(numer), denom(denom) {}
friend Rational operator*(const Rational& l, const Rational& r) {
std::cout << "Rational(" << l.numer << ", " << l.denom
<< ") * Rational(" << r.numer << ", " << r.denom << ")\n";
// calculate and return result
}
friend Rational operator/(const Rational& l, const Rational& r) { /* ... */ }
friend bool operator==(const Rational& l, const Rational& r) { /* ... */ }
};