class A {
public:
string operator+( const A& rhs ) {
return "this and A&";
}
};
string operator+( const A& lhs, const A& rhs ) {
return "A& and A&";
}
string operator-( const A& lhs, const A& rhs ) {
return "A& and A&";
}
int main() {
A a;
cout << "a+a = " << a + a << endl;
cout << "a-a = " << a - a << endl;
return 0;
}
//output
a+a = this and A&
a-a = A& and A&
I'm curious as to why the operator inside the class gets to be called rather than the outside one. Is there some sort of priority among operators?
The process of selecting amongst several functions of the same name is called overload resolution. In this code, the member is preferred because the non-member requires a qualification conversion (adding const to lhs) but the member does not. If you made the member function const (which you should, since it does not modify *this) then it would be ambiguous.
Whenever your object is non-const there's a priority of non-constness over constness. The inner will be called when the left side is non-const, and the outer will be called when the left side is const.
See what happens when the inner is defined as:
string operator+( const A& rhs ) const;
Related
As we know, we normally return a copy to a new class when overloading an arithmetic operator. As an example, << operator is normally defined like this:
T1 operator<<(const T1& a, const T2& b) {
// apply b
return a;
}
But I wonder if it is generally valid to return a reference in this case or not. For example, is it possible that following code creates any invalid situation?
T1& operator<<(T1& a, const T2& b) {
// apply b
return a;
}
Why I need this? Let's assume I have a code like this:
class B {
public:
B() {}
~B() { std::cout << ss_.str() << "\n"; }
template<typename T>
B& operator<<(T val) {
ss_ << val;
return *this;
}
private:
std::stringstream ss_;
};
int main() {
B{} << "str" << "abc" << 1;
B{} << "str2" << "abc2" << 2;
}
In this code, constructor and destructor of type T1 will be called only once which will be really suitable here. But if I return by value for the << operator, constructor and destructor will be called for each temporary rvalues which is not great for my use case.
Is it possible that returning by reference create invalid code for overloading these operators?
Yes, it's not only valid, it's a common idiom when overloading << for stream outputs. For example:
std::ostream& operator<<(std::ostream& os, const MyData& data) {
os << data.a << ',' << data.b << ',' << data.c;
return os;
}
The rule about returning a reference is to never return a reference to a function local variable. This also includes function parameters that are passed by value.
It gets a little trickier when dealing with reference parameters.
const T1& operator<<(const T1& a, const T2& b) {
// apply b
return a;
}
is problematic since a could be bound to a temporary. That would mean that you are returning a reference to an object that is going to end at the end of the full expression the function call is in, which could cause trouble.
Using
T1 operator<<(T1& a, const T2& b) {
// apply b
return a;
}
You stop that from happening as now a can only bind to an lvalue so you don't have to worry about it living past the full expression the function is called in.
Why am I allowed to do this, why there is no ambiguity complain, and why is the class' method chosen with prior to the other one?
class EX
{
public:
//...
void operator+(const EX& ref)
{
cout << "A";
}
};
void operator+(const EX& ref1, const EX& ref2)
{
cout << "B" << endl;
}
int main()
{
EX obj1{20};
EX obj2{30};
cout << "obj1 + obj2 = " << obj1 + obj2 << endl;
return 0;
}
I was expecting the global function operator+ to be called an "B" printed on the screen, instead "A" was printed.
Your member overload accepts only non-const instances of EX for the first operand while the free overload accepts both const and non-const instances. By overload resolution rules, the non-const wins out because it exactly matches the type being passed in.
You'll get an ambiguity error if you make the member overload const, indicating that *this is const:
void operator+(const EX& ref) const
{
cout << "A";
}
I'm trying to add two object that they are in the same class.
In the private section of the class I have two int variables
class One {
private:
int num1, num2;
public:
One operator+=(const One&); // - a member operator that adds another One object - to the current object and returns a copy of the current object
friend bool operator==(const One&, const One&); // - a friend operator that compares two One class objects for equality
};
One operator+(const One&, const One&);// - a non-friend helper operator that adds One objects without changing their values and returns a copy of the resulting One
I'm not sure I have a problem on the opeartor+ I guess
One operator+(const One &a, const One &b){
One c,d,r;
c = a;
d = b;
r += b;
r += a;
return r;
}
I think the above code is wrong, but I tried to use like b.num1 and I get compile error
error: 'int One::num1' is private
error: within this context
and I can't use b->num1 as well because the above function is not in the member function section.
error: base operand of '->' has non-pointer type 'const One'
This is how it calls in main
Result = LeftObject + RightObject;
If you have already implemented this member function:
One One::operator+=(const One&);
Then you may implement the non-member addition operator thus:
One operator+(const One& lhs, const One& rhs) {
One result = lhs;
result += rhs;
return result;
}
This can be simplified somewhat into the following:
One operator+(One lhs, const One& rhs) {
return lhs += rhs;
}
This pattern (which you can adapt for all operator/operator-assignment pairs) declares the operator-assignment version as a member -- it can access the private members. It declares the operator version as a non-friend non-member -- this allows type promotion on either side of the operator.
Aside: The += method should return a reference to *this, not a copy. So its declaration should be: One& operator+(const One&).
EDIT: A working sample program follows.
#include <iostream>
class One {
private:
int num1, num2;
public:
One(int num1, int num2) : num1(num1), num2(num2) {}
One& operator += (const One&);
friend bool operator==(const One&, const One&);
friend std::ostream& operator<<(std::ostream&, const One&);
};
std::ostream&
operator<<(std::ostream& os, const One& rhs) {
return os << "(" << rhs.num1 << "#" << rhs.num2 << ")";
}
One& One::operator+=(const One& rhs) {
num1 += rhs.num1;
num2 += rhs.num2;
return *this;
}
One operator+(One lhs, const One &rhs)
{
return lhs+=rhs;
}
int main () {
One x(1,2), z(3,4);
std::cout << x << " + " << z << " => " << (x+z) << "\n";
}
I can't see why the operator+ is wrong:
#include <stdio.h>
class One {
public:
One(int n1, int n2): num1(n1),num2(n2) {}
private:
int num1, num2;
public:
One operator+=(const One& o) {
num1 += o.num1;
num2 += o.num2;
return *this;
}
friend bool operator==(const One&, const One&); // - a friend operator that compares two One class objects for equality
void print() {
printf("%d,%d\n", num1, num2);
}
};
One operator+(const One& a, const One& b) {
One r(0,0);
r += b;
r += a;
return r;
}
int main() {
One a(1,2),b(3,4);
One r = a + b;
r.print();
}
Consider the following code:
class A
{
public:
A& operator=( const A& );
const A& operator+( const A& );
const A& operator+( int m );
};
int main()
{
A a;
a = ( a + a ) + 5; // error: binary '+' : no operator found which takes a left-hand operand of type 'const A'
}
Can anyone explain why the above is returned as an error?
"( a + a )" calls "const A& operator+( const A& )" and returns a constant reference which is then passed to "const A& operator+( int m )" if I'm not mistaken.
How can one fix the above error (without creating a global binary operator+ or a constructor that accepts an int) such that the statement inside main() is allowed?
which is then passed to "const A& operator+( int m )" if I'm not mistaken
No. Since the LHS is a const A& and RHS is an int, it will call*
[anyType] operator+ (int rhs) const
// ^^^^^ note the const here.
as you've only provided the non-const version const A& operator+( int m ), the compiler will complain.
*: Or operator+(const int& rhs) const or operator+(float rhs) const... The crucial point is that it must be a const method.
operator+ should return an instance, not a reference:
// as member function
A operator+(const A& other);
// as free function
A operator+(const A& left, const A& right);
To explain the specific problem is "returns a constant reference which is then passed to const A& operator+( int m )". Since you have a const reference, it cannot call that function because it's not a const method (i.e. const A& operator+( int m ) const).
That said, that is not the way to fix operator+. If you're returning a reference, what is it a reference to? A local in operator+ would be bad as you shouldn't return a reference to a local. A reference to a global would be bad because it will limit how your code can be used properly. A reference to allocated memory would be bad because it will leak memory. A reference to *this would be bad because then operator+ is acting like operator +=.
Because you are modifying the left-hand side object when adding. You can't do that with a const object. Take Samuel advice btw, because the idiomatic way is to return a new copy of the added objects.
The function needs to be const:
const A& operator+( int m ) const;
As const A& operator+( const A& ) returns a const reference a non-const member function const A& operator+( int m ) can not be called over a const object.
Either, the first operator should be defined as A& operator+( const A& ) or, the second operator as const A& operator+( int m )const;
However, these changes will only make them technically correct, not aesthetically in majority of the cases, as a binary operator is not supposed to modify any of the input argument and yet to compute a result and return. Thus the result have to be returned by value or in case of C++0x , as a r-value reference.
i.e A operator+(const A& rhs)const or A&& operator+(const A& rhs)const;
The problem is that (a+a) returns a so-called rvalue (basically a fancy term for a temporary). While you can invoke member functions on an rvalue, you can only invoke const member functions. Also, everyone is right in saying that operator+ must alwasys return a new value.
Your operators should be implemented like this:
A operator+( const A& ) const;
A operator+( int m ) const;
However, binary operators which don't modify their left argument are probably better implemented as free functions:
class A { ... };
A operator+(const A& lhs, const A& rhs);
A operator+(const A& lhs, int rhs);
Usually, they are implemented on top of operator+=, which is implemented as a member:
class A {
public:
A& operator+=(const A& rhs);
A& operator+=(int rhs);
};
inline A operator+(A lhs, const A& rhs) // note: lhs is passed by copy now
{
lhs += rhs;
return lhs;
}
A operator+(A lhs, int rhs) // note: lhs is passed by copy now
{
lhs += rhs;
return lhs;
}
I'm trying to overload the comma operator with a non-friend non-member function like this:
#include <iostream>
using std::cout;
using std::endl;
class comma_op
{
int val;
public:
void operator,(const float &rhs)
{
cout << this->val << ", " << rhs << endl;
}
};
void operator,(const float &lhs, const comma_op &rhs)
{
cout << "Reached!\n"; // this gets printed though
rhs, lhs; // reversing this leads to a infinite recursion ;)
}
int main()
{
comma_op obj;
12.5f, obj;
return 0;
}
Basically, I'm trying to get the comma operator usable from both sides, with a float. Having a member function only allows me to write obj, float_val, while having an additional helper non-friend non-member function allows me to write float_val, obj; but the member operator function doesn't get called.
GCC cries:
comma.cpp: In function ‘void operator,(const float&, const comma_op&)’:
comma.cpp:19: warning: left-hand operand of comma has no effect
comma.cpp:19: warning: right-hand operand of comma has no effect
Note:
I realise that overloading operators, that too to overload comma op., Is confusing and is not at all advisable from a purist's viewpoint. I'm just learning C++ nuances here.
void operator,(const float &rhs)
You need a const here.
void operator,(const float &rhs) const {
cout << this->val << ", " << rhs << endl;
}
The reason is because
rhs, lhs
will call
rhs.operator,(lhs)
Since rhs is a const comma_op&, the method must be a const method. But you only provide a non-const operator,, so the default definition will be used.