I still haven't figured out how the & works in the compiler.
To figure it out, I tried disassembling the code below:
private:
int data;
public:
int& at()
{
return data;
}
int at()
{
return data;
}
const int& result = mymay.at(); //call the two functions
I find that int& at() returns an address, and int at() returns a value; the compiler first writes the value to a memory, then "result"'s address was set to it.
So I understand that int at() will return a copied one.
I also understand that it's best practice to write friend ostream& operator<<(ostream &os , const A &obj)
But I wonder if it's correct: in the below code, A &get1() returns an l-value, and A get2() returns an r-value.
#include <iostream>
using namespace std;
class A
{
public:
A &get1(){
return *this;
}
A get2(){
return *this;
}
friend ostream& operator<<(ostream &os , A &obj){
cout<<"An l-value function called."<<endl;
return os;
}
friend ostream& operator<<(ostream &os , A &&obj){
cout<<"An r-value function called."<<endl;
return os;
}
};
int main()
{
A tmp;
cout<<"get1: "<<tmp.get1()<<"get2: "<<tmp.get2()<<endl;
return 0;
}
Actual results:
An l-value function called.
An r-value function called.
The version of at that returns a reference allows you to modify the member datum data via that reference:
mymay.at() = 1;
will set data in the instance of mymay to 1. So mymay.at() is an l-value: i.e. it can be placed on the left hand side of an assignment.
The version of at that returns a value will not allow you to do that. It's not an l-value.
Your second point, an l-value cannot bind to an rvalue reference && wheres an anonymous temporary can. Overload resolution for your cout is unambiguous which accounts for the output of your program.
Related
This question already has answers here:
What are the basic rules and idioms for operator overloading?
(8 answers)
Closed 1 year ago.
Firstly, i'm pretty new to C++ and OOP, so sorry if asking silly questions. So, here it is, I overloaded the "<<" and "++" (postfix and prefix) and they work fine alone. But they seem to not work when combined. I don't get why, both ++-s return a foo type object, so I thinked that "<<" should work fine...
#include <iostream>
using namespace std;
class foo
{
int x;
public:
foo()
{
x=10;
}
foo(const foo& f1)
{
this->x=f1.x;
cout<<"OK"; /// testing if it really works
}
foo operator ++ ()
{
++x;
return *this;
}
foo operator ++ (int)
{
x++;
return *this;
}
friend istream& operator>>(istream& in, foo& S);
friend ostream& operator<<(ostream& out, foo& S);
};
istream& operator>>(istream& in, foo& S)
{
in>>S.x;
return in;
}
ostream& operator<<(ostream& out, foo& S)
{
out<<S.x;
return out;
}
int main()
{
foo A, B, C;
cout<<A;
//cout<<++A; //error: cannot bind non-const lvalue reference of type 'foo&' to an rvalue of type 'foo'
//cout<<A++; //error: no match for 'operator<<' (operand types are 'std::ostream' {aka 'std::basic_ostream<char>'} and 'foo')
return 0;
}
Your stream output overload should take your foo references as const. After all, they shouldn't be modifying the foo's passed in:
friend istream& operator<<(istream& in, const foo& S);
A non-const reference parameter (like your foo& S), must have an l-value passed to it. Since your increment operator returns an r-value, you're seeing the compiler error (which says exactly this). To be able to take both l and r-values, you need to make the change to a const-reference parameter above.
In addition, your prefix increment operator should return by reference:
foo& operator ++ ()
{
++x;
return *this;
}
For more on the basic rules and idioms for overloading, read here: https://stackoverflow.com/a/4421719/2602718
In addition to scohe001's answer, your postfix and prefix operators also need correction.
Prefix operator should return a reference to the object being incremented. You're returning a copy of *this instead. Your return type should be foo& as such:
foo& operator ++ ()
{
++x;
return *this;
}
And in the postfix operator, you need to first remember the state of the object, i.e. make a copy of the object before modification, and then modify the object, and finally return the unmodified copy, like this:
foo operator ++ (int)
{
foo temp(*this);
++x;
return temp;
}
Here's your code, fixed up. I added comments where I made changes.
#include <iostream>
using namespace std;
class foo {
int x;
public:
foo() { x = 10; }
foo(const foo& f1) {
this->x = f1.x;
cout << "OK"; /// testing if it really works
}
// Changed return type
foo& operator++() {
++x;
return *this;
}
// Re-wrote body
foo operator++(int) {
foo tmp = *this;
++(*this);
return tmp;
}
friend istream& operator>>(istream& in, foo& S);
friend ostream& operator<<(ostream& out, const foo& S); // Added const
};
istream& operator>>(istream& in, foo& S) {
in >> S.x;
return in;
}
// Matched added const
ostream& operator<<(ostream& out, const foo& S) {
out << S.x;
return out;
}
int main() {
foo A, B, C;
cout << A << '\n';
cout << ++A << '\n';
cout << A++ << '\n';
return 0;
}
Prefix ++ and postfix ++ behave differently. This is observed when testing the operators out on a regular int.
int x = 5;
std::cout << x++ << '\n';
std::cout << ++x << '\n';
You get the output:
5
7
Postfix increment returns the original value but still increments. Prefix increment returns the incremented value. This is why prefix needs to return a reference. It returns itself, and we do that with a reference.
So what happened in the short code example above was x had its original value (5) returned, but the postfix increment still incremented, so x had a value of 6. Then the prefix print ensured that the incremented x was returned and it printed 7.
The change to operator<<() is convention. When printing an object, I don't want to modify it, so I pass it as a reference to const.
I have one doubt on prefix operator overloading .
my sample program:
class ABC {
int i;
public:
const ABC& operator++() { i=i+1; return *this;}
};
int main() {
ABC ob ; //let value of i =5;
++ob; // value of i will be 6
return 0;
}
but I could do the same thing by overloading like below
void operator++() { i=i+1;}
this gives me same result when calling ++ob
APMK ++ob converted as ob.operator++().
My doubt is what happens to the return value. Does the compiler creates code like:
ob = ob.operator++();
Thanks in advance
why do we have to return const reference from unary prefix operator overloading
You don't have to. Typically you return non-const reference, but you could make it return anything. You shouldn't, but you could. The built in pre-increment works how returning non-const reference works, so it makes the most sense to do that.
The reason to return a reference to an object is to make the behavior the same as for integers (for built in types).
std::cout << ++i;
std::cout << i++;
If i is an integer this will work. This will only work in a class if you return a reference to the object (Assuming you have defined operator<< for your class).
class ABC {
int i;
public:
ABC(int x = 0) : i(x) {}
const ABC& operator++() { i=i+1; return *this;}
ABC operator++(int) { ABC result(*this);i=i+1; return result;}
friend std::ostream& operator<<(std::ostream& out, ABC const& val)
{
return out << val.i;
}
};
With this definition then your class will behave the same way that an integer will behave in the above situation. Which makes it very useful when using template as you can now do a drop in replacement for integer with your type.
Note normally I would return just a reference (not a const reference).
/*const*/ ABC& operator++() { i=i+1; return *this;}
^^^^^^^^^
see: https://stackoverflow.com/a/3846374/14065
But C++ allows you do anything and you can return whatever is useful or has appropriate meaning for the situation. You should consider what is meaningful for your class and return a value that is appropriate. Remember the Principle of lease surprise
This prints an error message about qualifiers but don't really understand what that means and how to adjust the code for it to work? Anyways, thanks a lot for looking at the code.
Note: The ostream operator is friended in the Node class.
using namespace std;
ostream& operator(ostream& output, const Node* currentNode)
{
return output;
}
void Node::nodeFunction()
{
//This node has items attached to the 'this' statement. After
//the necessary functions, this is called to output the items.
cout << this;
}
Your overloaded stream operator declaration should be like this:
std::ostream& operator<<(std::ostream& os, const T& obj);
^^^^^^^^^^^^^
You should be returning a reference to object of std::ostream, the & is wrongly placed in your overloaded function prototype.
Have a look at the working sample here.
Adding the source code here, for completeness.
Note: I have taken class Node members as public for ease of demonstration.
#include<iostream>
using namespace std;
class Node
{
public:
int i;
int j;
void nodeFunction();
friend ostream& operator <<(ostream& output, const Node* currentNode);
};
ostream& operator<<(ostream& output, const Node* currentNode)
{
output<< currentNode->i;
output<< currentNode->j;
return output;
}
void Node::nodeFunction()
{
//This node has items attached to the 'this' statement. After
//the necessary functions, this is called to output the items.
cout << this;
}
int main()
{
Node obj;
obj.i = 10;
obj.j = 20;
obj.nodeFunction();
return 0;
}
The & on the return value of the operator is in the wrong place, and it's generally better to use references rather than pointers for ostream operators:
ostream& operator<<(ostream &output, const Node ¤tNode)
{
// Output values here.
return output;
}
void Node::nodeFunction()
{
cout << *this;
}
Here's a simplified version of my problem. I have a property class. It has data like has_initalized and such which i removed for this example.
When i call a function which uses T its fine. However T& isnt so i decided to write a T& version of it. But this causes all functions which uses plain T to get a compile error. Why is T& interfering with that? For this example how do i get both functions (Q and W) to work without changing main()?
template <class T>
class Property {
T v;
Property(Property&p) { }
public:
Property() {}
T operator=(T src) { v = src; return v; }
operator T() const { return v; }
operator T&() const{ return v; }
T operator->() { return v; }
};
class A{};
void Q(A s){}
void W(A& s){}
int main(){
Property<A> a;
Q(a);
W(a);
}
There is nothing in the overloading rules of C++ which allows the compiler to choose between operatorT() and operatorT&() in the call to Q. So removing the
operator T() const { return v; }
will also remove the ambiguity. But then you'll have a problem because returning a non const reference to a member in a const function is not possible.
For your Q, you can use both conversion functions. You can make the compiler prefer one over the other by making one non-const.
operator T() const { return v; }
operator T&() { return v; }
Now for Q, the operator T& is taken. This way will also fix the call to W to get a non-const reference. You can also return a const reference from the other
operator T const&() const { return v; }
operator T&() { return v; }
This way will still prefer the second conversion function for Q, but if your object a is const and you initialize a const reference, you won't always require to copy v.
In a project I'm working on, I have a Score class, defined below in score.h. I am trying to overload it so, when a << operation is performed on it, _points + " " + _name is printed.
Here's what I tried to do:
ostream & Score::operator<< (ostream & os, Score right)
{
os << right.getPoints() << " " << right.scoreGetName();
return os;
}
Here are the errors returned:
score.h(30) : error C2804: binary 'operator <<' has too many parameters
(This error appears 4 times, actually)
I managed to get it working by declaring the overload as a friend function:
friend ostream & operator<< (ostream & os, Score right);
And removing the Score:: from the function declaration in score.cpp (effectively not declaring it as a member).
Why does this work, yet the former piece of code doesn't?
Thanks for your time!
EDIT
I deleted all mentions to the overload on the header file... yet I get the following (and only) error. binary '<<' : no operator found which takes a right-hand operand of type 'Score' (or there is no acceptable conversion)
How come my test, in main(), can't find the appropriate overload? (it's not the includes, I checked)
Below is the full score.h
#ifndef SCORE_H_
#define SCORE_H_
#include <string>
#include <iostream>
#include <iostream>
using std::string;
using std::ostream;
class Score
{
public:
Score(string name);
Score();
virtual ~Score();
void addPoints(int n);
string scoreGetName() const;
int getPoints() const;
void scoreSetName(string name);
bool operator>(const Score right) const;
private:
string _name;
int _points;
};
#endif
Note: You might want to look at the operator overloading FAQ.
Binary operators can either be members of their left-hand argument's class or free functions. (Some operators, like assignment, must be members.) Since the stream operators' left-hand argument is a stream, stream operators either have to be members of the stream class or free functions. The canonical way to implement operator<< for any type is this:
std::ostream& operator<<(std::ostream& os, const T& obj)
{
// stream obj's data into os
return os;
}
Note that it is not a member function. Also note that it takes the object to stream per const reference. That's because you don't want to copy the object in order to stream it and you don't want the streaming to alter it either.
Sometimes you want to stream objects whose internals are not accessible through their class' public interface, so the operator can't get at them. Then you have two choices: Either put a public member into the class which does the streaming
class T {
public:
void stream_to(std::ostream&) const {os << obj.data_;}
private:
int data_;
};
and call that from the operator:
inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
obj.stream_to(os);
return os;
}
or make the operator a friend
class T {
public:
friend std::ostream& operator<<(std::ostream&, const T&);
private:
int data_;
};
so that it can access the class' private parts:
inline std::ostream& operator<<(std::ostream& os, const T& obj)
{
os << obj.data_;
return os;
}
Let's say you wanted to write an operator overload for + so you could add two Score objects to each other, and another so you could add an int to a Score, and a third so you could add a Score to an int. The ones where a Score is the first parameter can be member functions of Score. But the one where an int is the first parameter can't become member functions of int, right? To help you with that, you're allowed to write them as free functions. That is what is happening with this << operator, you can't add a member function to ostream so you write a free function. That's what it means when you take away the Score:: part.
Now why does it have to be a friend? It doesn't. You're only calling public methods (getPoints and scoreGetName). You see lots of friend operators because they like to talk directly to the private variables. It's ok by me to do that, because they are written and maintained by the person maintaing the class. Just don't get the friend part muddled up with the member-function-vs-free-function part.
You're getting compilation errors when operator<< is a member function in the example because you're creating an operator<< that takes a Score as the first parameter (the object the method's being called on), and then giving it an extra parameter at the end.
When you're calling a binary operator that's declared as a member function, the left side of the expression is the object the method's being called on. e.g. a + b might works like this:
A a;
B b
a.operator+(b)
It's typically preferable to use non-member binary operators (and in some cases -- e.g. operator<<for ostream is the only way to do it. In that case, a + b might work like this:
A a;
B b
operator+(a, b);
Here's a full example showing both ways of doing it; main() will output '55' three times:
#include <iostream>
struct B
{
B(int b) : value(b) {}
int value;
};
struct A
{
A(int a) : value(a) {}
int value;
int operator+(const B& b)
{
return this->value + b.value;
}
};
int operator+(const A& a, const B& b)
{
return a.value + b.value;
}
int main(int argc, char** argv)
{
A a(22);
B b(33);
std::cout << a + b << std::endl;
std::cout << operator+(a, b) << std::endl;
std::cout << a.operator+(b) << std::endl;
return 0;
}