I'm implementing a fraction class, and need to overload arithmetic operators.
The problem is, can I only implement a const version.
For example, addition:
Fraction operator+( const Fraction& other ) const;
Since both non-const, and const Fraction objects can call this function, do I still need to have an non-const operator+ member function?
const member functions can be called on non-const objects, so no, you don't need a non-const overload.
Fraction a, b;
Fraction c = a + b; // no problem
In general, this kind of problem is better solved with a member operator+= and a nonmember operator+, like this:
class Fraction {
public:
const Fraction& operator+=(const Fraction&);
};
Fraction operator+(const Fraction& lhs, const Fraction& rhs) {
Fraction res(lhs);
res += rhs;
return res;
}
No. You can call const methods over non-const objects, exactly as you can have const references bind to non-const objects. IOW, you can always pass an object that you can modify to code that promises not to modify it - there's no loss of safety. The opposite of course is not true - if you have a const object (=> an object you promised not to modify) you cannot pass it to code that doesn't adhere to this promise.
Related
Suppose I have a class called Complex, why I'm allowed to define the following function:
Complex operator+(Complex& c1, Complex& c2);
But I can't write:
Complex operator**(Complex& c1, Complex& c2);//for power
** is not a valid C++ operator on its own, it is simply two * operators with no whitespace. We cannot create new operators in C++, but operator* can be overloaded as an unary or a binary operator. operator* can be implemented as a non-member function, member function, or friend function, depending on the class structure. Below is an example of operator* implemented as a binary, non-member function, which returns a new Example object.
struct Example {
int x;
};
Example operator*(Example a, const Example& b){
return a *= b;
}
From over.oper, you can see which operators can be overloaded. You will notice that ** is not one of the valid operators to overload. There is, however, the ^ operator you can use (although it's usually meant for bitwise)
As mentioned in the comments, you cannot create new operators this way, so you cannot make a new one for **
I Have a Fraction Class.
I need to do 3 operations on Fraction Object i.e
Multiply two Fraction objects. e.g F1*F2
Multiply a Fraction object by an integer. For ex. F1*3
Multiply an integer by a Fraction object. For ex. 3*F1.
The first two case can be achieved by overriding the Fraction Class * operator.
Fraction operator*(const Fraction&);
Fraction operator*(const int&);
but how to multiply an integer by a fraction Object? The third case
Any Suggestions??
PS: I don't want to treat integer as a Fraction object e.g (3/1) and then doing the multiplication.
You need to implement the operator overload as a free function, like this:
Fraction operator *(int lhs, Fraction rhs)
{
rhs *= lhs;
return rhs;
}
Note that I have implemented the function in terms of Fraction::operator*=(int) (see here why this is considered good practice). If this function is not present, you might want to pass the second parameter as const Fraction& rhs and provide a different implementation.
Besides, note that an idiomatic way to handle this scenario is to allow an implicit construction of Fraction instances by a single int argument, so your constraint seems a bit awkward to me. Further note that users of your Fraction class might expect all arithmetic operations to be possible (why should there be operator*, but not operator/?). To reduce the amount of manual code to be written in such cases, the boost operator library can be of great help.
Can I make a case for the inplace friend function?
In c++11 you can declare and write your friend function inside the class, which can make it much neater:
class MyNumber
{
private:
Clever c;
Clever Multiply (Clever, i) { ... }
public:
MyNumber operator * (int i)const { return Multiply(c,i) }
MyNumber operator * (const MyNumber &i)const { ... }
const MyNumber& operator *= (int i) { return c= Multiply(c, i); }
// introducing the inline friend (presuming multiply is commutative/symmetric here)
friend MyNumber operator (int i, const MyNumber& j) { return j.Multiply(c,i); }
};
Note that this friend function is still actually a global function, and has access to the class internals, but its implementation is now tidily inside the class definition.
The neatness of this style is such that I am tempted to use it even when I don't actually need the dirty friend access.
With these math overloading objects, also consider the RValue substitution overloads. An rvalue implementation of binary multiply implemented as mult-assign can show some efficiencies, though perhaps not soo much with only a 2-value fraction class.
There are three different ways to overload operators: the member function way, the friend function way, and the normal function way.
In this specific case we need overload the operators in friend function way.
friend Fraction operator*(const Fraction &a, const Fraction &b); //F1*F2
friend Fraction operator*(const Fraction &a, int b); //F1*3
friend Fraction operator*(int a, const Fraction &b); //3*F1
Is it right to define operator += in this way ?!
void operator +=(const BigNumber& other)
{
*this=(*this) + other;
}
In a class like this :
class BigNumber
{
public:
//....
BigNumber operator +(const BigNumber& other)
{
return sum(other);
}
//....
}
Yes. But the right way is to implement operator+ in terms of operator+=:
struct foo
{
int value;
foo& operator+=( const foo& other )
{
value += foo.value;
return *this ;
}
friend foo operator+( foo lhs , const foo& rhs )
{
return lhs += rhs;
}
};
Why?
First of all, the binary operator+() shouldn't be defined as member function instead of free function. This allows you to implement addition where the first parameter is not a foo. The common idiom is to declare it friend inside the class to ride over encapsulation.
Second, this way provides a coherent, maintainible, and efficient interface.
Coherency:
If you implement a += operation, the user spects (Except in rare cases) the type provides a binary addition too. Implementing + with += provides this ensuring that the behavior of the two operations is coherent.
Maintainability:
You have implemented + using +=, so the code which really performs the addition is written only once. If you need to change the operation in the future you have to change one code only, and if it has a bug that bug is in one site only. Reducing code duplication is a good practice in general.
Efficiency:
The way the operator+() is written allows the compiler to easily elide copies, boosting the performance of the binary addition.
The idiom used is "copy first operand, operate on it, return the copy". So the compiler can easily perform a return value optimization (RVO). Also, it passes the first operand by value instead of copying the operand by hand inside the function. This allows the compiler to perform more copy elisions when the first operand is an rvalue (Let the compiler decide when and how to copy).
Yes you can do it your way:
BigNumber& operator +=(const BigNumber& other)
{
*this=(*this) + other;
return *this;
}
The usual approach is the opposite way:
// Note a is no const reference
BigNumber operator + (BigNumber a, const BigNumber& b)
{
return a += b;
}
A reasoning for your approach might be memory allocation.
The other day, I ran into trouble when I tried to overload a two-parameter operator with the use of a class member function. I tried references, but nothing changed. The compiler said I couldn't write a member function that takes more than one argument of the same type as the class itself. Why is that?
Here is the code:
class Fraction
{
public:
Fraction(int num=1, int den=1): numerator(num), denominator(den) {}
Fraction(const Fraction& r): numerator(r.numerator), denominator(r.denominator) {}
Fraction& operator=(const Fraction&);
Fraction& operator*(const Fraction&, const Fraction&);
private:
int numerator, denominator;
};
Fraction& Fraction::operator=(const Fraction& r)
{
numerator = r.numerator;
denominator = r.denominator;
return *this;
}
Fraction Fraction::operator*(const Fraction& x, const Fraction& y)
{
Fraction z(x.numerator*y.numerator, x.denominator*y.denominator);
return z;
}
The following is the error message from the compiler:
Fraction& Fraction::operator*(const Fraction&, const Fraction&)' must take either zero or one argument
The operators take a fixed amount of arguments, for example operator+ as the addition operator takes exactly 2 parameters. If it is a member function the first(leftmost) is implied to be this and the second is passed as a parameter.
What would calling an operator+ that took three parameters look like? One might imagine it would look like 3 + 4 + 5 but that is the equivalent of calling operator+(3,4) then operator+(7,5).
For a list of operators and how many arguments they take please check out wikipedia: http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B
For more details there is another StackOverflow post that goes into great detail: Operator overloading
Firstly, the issue you are observing has absolutely nothing to do with member functions in general. Member functions can generally take arbitrary number of arguments of "same class" type. In your example you can declare
class Fraction
{
void foo(Fraction &f1, Fraction &f2, Fraction &f3, Fraction &f4) {}
...
};
without any problems. So, it is not clear why you decided to word your question as if it is about member functions in general.
Secondly, in your code it is really about the simple fact that you are trying to overload an operator. Operator syntax in C++ is fixed for most (but not all) operators. This immediately means that those operators whose syntax is fixed will have fixed number of parameters.
In your example, it is operator *. It can be unary (one parameter) or binary (two parameters). When you overload this operator by a member function one parameter is already implied, so you can only add zero or one additional parameters (for unary * and binary * respectively). You, on the other hand, are trying to add two more parameters in additions to the implicit one. I.e. you are trying to define a ternary operator *. This is not possible. There's no ternary * operator in C++. And this is exactly what the compiler is telling you.
I read that implementing operators as friend function will be better. How to overload += operator as a friend function when I already have + operator function:
friend Dollar operator+(const Dollar &p1, const Dollar &p2);
friend Dollar &operator+=(const Dollar &p1, const Dollar &p2);
This is wrong since I need to return a reference to a variable.
Dollar &operator+=(const Dollar &p1, const Dollar &p2)
{
return p1+p2;
}
Overloading operators as friend functions is better in order to allow conversions to apply to both the left and right side of the expression. For example, string's operator+ is a friend so that I can write "Hello " + string("World") rather than only being able to write string("Hello ") + "World".
However, this reasoning doesn't apply to mutators such as operator+=. You have to take a non-const left argument, which precludes being able to use this operator on a temporary. For this reason, it's recommended to implement non-mutating operators as friend (or otherwise free-) functions and mutators as member functions. (In fact, operator= can only be overloaded as a member function.)
You also need to modify the lvalue.
Dollar &operator+=(Dollar &p1, const Dollar &p2)
{
p1=p1+p2;
return p1;
}
The usual approach is to provide += as a member function that modifies *this and to implement + as a free function that uses +=.