This question already has answers here:
What are the basic rules and idioms for operator overloading?
(8 answers)
Closed 3 years ago.
According to Can't Overload operator<< as member function
When overloaded as a member function, a << b is interpreted as
a.operator<<(b), so it only takes one explicit parameter (with this as
a hidden parameter).
Since this requires that the overload be part of the class used as the
left-hand operand, it's not useful with normal ostreams and such. It
would require that your overload be part of the ostream class, not
part of your class. Since you're not allowed to modify ostream class,
you can't do that. That leaves only the global overload as an
alternative.
I know that for example:
friend std::ostream& operator<< (std::ostream &out, const Obj &obj);
acts like a function that takes an object of ostream and some object that you are trying to print and then returns an ostream object.
But I don't understand how doing cout << obj will call this function.
Wouldn't cout << obj do something like cout.operator<<(obj), which is exactly what we don't want? So why does it actually call the function? And why does it allow the return value to go back to cout?
EDIT:
I had read over What are the basic rules and idioms for operator overloading? previously and it states
"A binary infix operator #, applied to the objects x and y, is called
either as operator#(x,y) or as x.operator#(y).4"
which provides some further clarity, but I don't see how it answers my question.
That's exactly what the answer you quote says, although it doesn't do so very well.
An operator overload can be a member, or a non-member.
For example, anOstream << aT can be resolved with a ostream& ostream::operator<<(T) (or similar) or with a free function ostream& operator<<(ostream&, T). Either of those can be called. That's just how it is. That's what the standard says.
Since we can't add things to ostream, the latter is how we go about it (though, for your own types, it would be pretty much up to you).
Notice how I chose a return type of ostream& for those examples; that's how "the return value goes back to cout": the left-hand operand is simply returned back by reference.
The compiler would call cout.operator<<(obj) if it was present but if it isn't it will look for a compatible global function.
e.g. Below it will call the member function. But if that is commented out it will call the global function.
#include <iostream>
class Ostr;
class Obj {
public:
void print(Ostr& os) const;
};
class Ostr {
public:
Ostr& operator<<(const Obj& obj){
std::cout << "member";
obj.print(*this);
return *this;
}
Ostr& operator<<(const char* obj){
std::cout << obj;
return *this;
}
};
void Obj::print(Ostr& os) const {
os << "Obj";
}
template<class T>
auto operator<<(Ostr& os, const T& t) -> decltype(t.print(os), os) {
os << "global";
t.print(os);
return os;
}
int main() {
Obj obj;
Ostr ostr;
ostr << obj;
return 0;
}
Related
It is often overloaded as a friend function of the class. Is there any way it can be overloaded as a member function?
Is there any way it can be overloaded as a member function?
Let's say if you have a class Foo and you want to use:
Foo foo;
std::cout << foo;
No, it cannot.
A member function overload works only if the first argument is an object of the class. In the case of stream insertion operators, the first argument is a stream, not an object of the class.
If you want to use:
Foo foo;
foo << std::cout;
Yes, it can be defined as a member function.
A non-member function and a virtual member function can be combined to good effect when used in a situation where derived classes are involved.
struct Shape
{
// Member function that can be overridden by derived classes.
virtual std::ostream& operator<<(std::ostream& os) const = 0;
};
// Non-member function that makes use of member functions.
std::ostream& operator<<(std::ostream& os, Shape const& shape)
{
return shape << os;
}
struct Rectangle : public Shape
{
virtual std::ostream& operator<<(std::ostream& os) const
{
// Do the need full to stream a Rectangle.
// ...
return os;
}
};
struct Ellipse : public Shape
{
virtual std::ostream& operator<<(std::ostream& os) const
{
// Do the need full to stream an Ellipse.
// ...
return os;
}
};
Usage:
Rectangle r;
Ellipse e;
std::cout << r << std::endl;
std::cout << e << std::endl;
If you wanted to badly enough, you could use a member function overload, but it's directly contrary to convention, so doing it would lead to confusion. It would also prevent chaining extraction/insertion operators, and wouldn't work for reading/writing primitive types.
The reason behind this is that invoking an operator overloaded as a member function means that x << y; is interpreted as x.operator<<(y);, so the overloaded operator has to be a member of the left operand, not the right. It's possible to do that (iostreams include such overloads for some types), but it's essentially impossible to extend (all such overloads have to be part of the iostream object when it's the left operand).
If you want to overload it as a member of the object to be read/written, you need to put the object being read/written as the left operand. This means insertion would go from left to right instead of right to left. To have at least some chance of maintaining sanity, you'd almost certainly want to use >> for insertion, and << for extraction:
class my_class {
int x;
public:
bool operator<<(std::istream &is) {
// Note the reversal here. That's because we're defining this
// for a `my_class` on the left, and an iostream on the right,
// but the existing `>>` and `<<` use the reverse of that (iostream
// on the left).
is >> x;
return is.good();
}
bool operator>>(std::ostream &os) {
os << x;
return os.good();
}
};
my_class a;
a >> std::cout;
a << std::cin;
Note: I'm providing this answer only to point out that it's technically possible to do this, and show how. If you were starting over with a clean slate and you were really set on using member functions, I can see where you might conceivably choose this method--but even then, it's open to a lot of question.
In particular (as noted above) this would not support chaining. Since the insertion and extraction are done as member functions of the left operand, it also means it would only work for user-defined types, not any primitive types (int, short, long, float, double, bool, etc.)
Bottom line: if you want to badly enough, you can get it to work to a limited degree under limited circumstances--but neither well (no chaining) nor universally (no primitive types).
Is there any way it can be overloaded as a member function?
No. The signature of the function prevents this option.
// Binary operator where the stream object is left of '<<' and the object
// instance is right of '<<'
std::ostream& operator<<(std::ostream& lhs, const Foo& rhs)
For illustration here's a binary operator+ as a free function:
class Foo
{
};
Foo operator+(const Foo& lhs, const Foo& rhs)
{
// an appropriate implementation
}
int main()
{
Foo f1;
Foo f2;
// Uses the free function
Foo result = f1 + f2;
return 0;
}
However implemented as a member function it looks like this:
class Foo
{
public:
Foo operator+(const Foo& other) const
{
// an appropriate implementation
}
};
int main()
{
Foo f1;
Foo f2;
// The calling sequence is the same as before however 'f1' is logically
// the same as 'lhs' in the free function implementation example (i.e.,
// the first type in the binary operator must be the class type when
// implemented as a member function)
Foo result = f1 + f2;
return 0;
}
Given the operator+ member function example it is easier to see why the std::ostream& operator<<(std::ostream& lhs, const Foo& rhs) free function cannot be converted to an equivalent member function. Because 'lhs' would need to be the same type as std::ostream but this is only possible when implementing that class whereas in this example the Foo class is being implemented.
int i=0;
std::cout << i;
1, The non-member overload(two arguments, one being ostream& the other being type of operand, say int) is defined in std namespace. So if using namespace std; is not present, there's no way I see that the non-member overload can be called.
2, If instead, the member operator(member of ostream; one argument, being the type of operand, say int) function << of ostream is called, I'd expect something like: std::cout.operator<< i; --- isn't this rediculous?
So, what on earth is the relation between the two?
Question extended: if I want to overload the insertion operator so that std::cout << my_obj; works(assume my_obj is the instance of a user-defined type, MyType), should I do
a) ostream& operator<< (ostream& os, MyType obj); in the namespace of MyType
or
b) in MyType:
class MyType
{
...
ostream& operator<< (MyType);
};
does option b) ever work? Does it even make sense(I remember seeing it somewhere ...)? What's the relation between option a) & b)?
EDIT MAR 27
Upon the request from ecatmur, here're two overloads that have the same signature but in different namespaces. Using gcc 4.9.2: http://melpon.org/wandbox/
#include <iostream>
namespace MyNameSpace
{
class MyType
{};
// signature can be found here: http://www.cplusplus.com/reference/ostream/ostream/operator-free/
std::ostream& operator<<(std::ostream& out, char ch)
{
out << "std is doomed\n";
return out;
}
std::ostream& operator<<(std::ostream& out, MyType t)
{
out << "std is super doomed\n";
return out;
}
}
int main()
{
MyNameSpace::MyType t;
std::cout << t; // ... super doomed; ADL is working as intended.
std::cout << 't'; // t; this proves that when there're two operator overloads with the same signature but in different namespaces, there're no compilation errors. gcc defaults to the std one.
return 0;
}
The non-member overloads you're thinking of are those for character data and those for std::string etc.; they're available via argument-dependent lookup. You can indeed write std::cout.operator<<(i) for types where ostream has a member operator<<.
For your own types you're thinking of a (non-member) friend operator<<, which can be particularly useful for template classes (the Barton-Nackman trick) or for those where the operator<< accesses data not available via accessors:
class MyType
{
...
friend std::ostream& operator<< (std::ostream&, MyType obj) { ... }
};
Your proposed signature would allow you to write my_obj << my_obj, which is unlikely to make much sense.
For example, if I wanted to pass
ostream& std::ostream::operator << (int i);
into a function such as
void func(ostream& (*out)(int), ...);
then how would I go about doing that?
Doing
func(std::ostream::operator << (int))
surely does not work and
typedef ostream& (*out)(int);
out o = std::ostream::operator << (int);
func(o);
throws a compile-time error when trying to assign o. So how does one point to overloaded operators? (casting to type out does not work in this situation either)
After playing around with the code, my question is now this: why is it that non-member, overloaded operators i.e
ostream& operator << (ostream&, classX)
return a void* and not a pointer to a function?
If I do
typedef ostream& (*out)(ostream&,classX);
I can only make it
void* v = ostream& operator << (ostream&,classX);
and not
out o = ostream& operator << (ostream&,classX);
which prints the error messsage
190: error: invalid conversion from 'void*' to 'std::ostream& (*)(std::ostream&, classX)'
Depend on how you have overloaded the operator.
The signature (The type of the pointer that points to) of a function is:
RETURN_TYPE(*)(PARAMETERS_TYPES) if its a global function.
RETURN_TYPE (CLASS_NAME::*)(PARAMETERS_TYPES) if its a member function.
If you have a function called f and a function that gets a pointer to a function as parameter, f is passed as follows:
g(f) if f is a global function.
g(&CLASS_NAME::f) if f is a member function of CLASS_NAME class.
Note that function pointers and member function pointers are not compatible.
So if your operator is overloaded as a member function, like operator+= you should use the second version. If not, you should use the first.
I would simplify the assignment here. There is no need to specify the whole signature, since the correct overload can be inferred from the type on the left hand side.
#include <iostream>
using namespace std;
struct Foo
{
int x;
};
ostream& operator<< (ostream &a, const Foo& b)
{
return a << b.x;
}
typedef ostream& (*Func) (ostream &, const Foo&);
int main() {
Func func = &operator<<;
(*func)(cout, Foo{42});
}
a.h
#include "logic.h"
...
class A
{
friend ostream& operator<<(ostream&, A&);
...
};
logic.cpp
#include "a.h"
...
ostream& logic::operator<<(ostream& os, A& a)
{
...
}
...
When i compile, it says:
std::ostream& logic::operator<<(std::ostream&, A&)' must take exactly one argument.
What is the problem?
The problem is that you define it inside the class, which
a) means the second argument is implicit (this) and
b) it will not do what you want it do, namely extend std::ostream.
You have to define it as a free function:
class A { /* ... */ };
std::ostream& operator<<(std::ostream&, const A& a);
A friend function is not a member function, so the problem is that you declare operator<< as a friend of A:
friend ostream& operator<<(ostream&, A&);
then try to define it as a member function of the class logic
ostream& logic::operator<<(ostream& os, A& a)
^^^^^^^
Are you confused about whether logic is a class or a namespace?
The error is because you've tried to define a member operator<< taking two arguments, which means it takes three arguments including the implicit this parameter. The operator can only take two arguments, so that when you write a << b the two arguments are a and b.
You want to define ostream& operator<<(ostream&, const A&) as a non-member function, definitely not as a member of logic since it has nothing to do with that class!
std::ostream& operator<<(std::ostream& os, const A& a)
{
return os << a.number;
}
I ran into this problem with templated classes.
Here's a more general solution I had to use:
template class <T>
class myClass
{
int myField;
// Helper function accessing my fields
void toString(std::ostream&) const;
// Friend means operator<< can use private variables
// It needs to be declared as a template, but T is taken
template <class U>
friend std::ostream& operator<<(std::ostream&, const myClass<U> &);
}
// Operator is a non-member and global, so it's not myClass<U>::operator<<()
// Because of how C++ implements templates the function must be
// fully declared in the header for the linker to resolve it :(
template <class U>
std::ostream& operator<<(std::ostream& os, const myClass<U> & obj)
{
obj.toString(os);
return os;
}
Now:
* My toString() function can't be inline if it is going to be tucked away in cpp.
* You're stuck with some code in the header, I couldn't get rid of it.
* The operator will call the toString() method, it's not inlined.
The body of operator<< can be declared in the friend clause or outside the class. Both options are ugly. :(
Maybe I'm misunderstanding or missing something, but just forward-declaring the operator template doesn't link in gcc.
This works too:
template class <T>
class myClass
{
int myField;
// Helper function accessing my fields
void toString(std::ostream&) const;
// For some reason this requires using T, and not U as above
friend std::ostream& operator<<(std::ostream&, const myClass<T> &)
{
obj.toString(os);
return os;
}
}
I think you can also avoid the templating issues forcing declarations in headers, if you use a parent class that is not templated to implement operator<<, and use a virtual toString() method.
Operator overloading includes member function overloading and non-member function overloading, which cannot be mixed. https://condor.depaul.edu/ntomuro/courses/262/notes/lecture3.html
If you define operator<< as a member function it will have a different decomposed syntax than if you used a non-member operator<<. A non-member operator<< is a binary operator, where a member operator<< is a unary operator.
// Declarations
struct MyObj;
std::ostream& operator<<(std::ostream& os, const MyObj& myObj);
struct MyObj
{
// This is a member unary-operator, hence one argument
MyObj& operator<<(std::ostream& os) { os << *this; return *this; }
int value = 8;
};
// This is a non-member binary-operator, 2 arguments
std::ostream& operator<<(std::ostream& os, const MyObj& myObj)
{
return os << myObj.value;
}
So.... how do you really call them? Operators are odd in some ways, I'll challenge you to write the operator<<(...) syntax in your head to make things make sense.
MyObj mo;
// Calling the unary operator
mo << std::cout;
// which decomposes to...
mo.operator<<(std::cout);
Or you could attempt to call the non-member binary operator:
MyObj mo;
// Calling the binary operator
std::cout << mo;
// which decomposes to...
operator<<(std::cout, mo);
You have no obligation to make these operators behave intuitively when you make them into member functions, you could define operator<<(int) to left shift some member variable if you wanted to, understand that people may be a bit caught off guard, no matter how many comments you may write.
Almost lastly, there may be times where both decompositions for an operator call are valid, you may get into trouble here and we'll defer that conversation.
Lastly, note how odd it might be to write a unary member operator that is supposed to look like a binary operator (as you can make member operators virtual..... also attempting to not devolve and run down this path....)
struct MyObj
{
// Note that we now return the ostream
std::ostream& operator<<(std::ostream& os) { os << *this; return os; }
int value = 8;
};
This syntax will irritate many coders now....
MyObj mo;
mo << std::cout << "Words words words";
// this decomposes to...
mo.operator<<(std::cout) << "Words words words";
// ... or even further ...
operator<<(mo.operator<<(std::cout), "Words words words");
Note how the cout is the second argument in the chain here.... odd right?
The key point is the logic:: before operator<< which is defined as a friend function.
logic:: is only added before the member function. I understand that this is similar to telling the compiler that this function is a member function and granting it corresponding permissions (such as accessing private functions).
In other words, just as #asaelr and #Morteza mentioned, "when defining a friend function you do not use the name of the class to scope the name of the friend function".
Hence, we should remove logic:: before operator<<.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
When should you use 'friend' in C++?
There is a detailed explanation here, but I would like to know what is the practical use of Friend function.
How I can decide when I should go with a friend function rather than a member function?
In most cases, friend declarations are a code-smell since it breaks encapsulation.
Developers often use friend for a quick-fix to a problem. However a good starting design or some refactoring (more often more than less) exclude the necessity for it.
EDIT:
Even in #Darhuuk's example, a friend declaration is not needed. You can have getters for the specific fields you want to print.
You would use a friend when the function needs to be a non-member, but also needs access to class members.
Common examples where you need a non-member function are:
An API that requires non-member functions; for example, boost::intrusive_ptr requires that you implement intrusive_add_ref() and intrusive_release() as non-member functions.
Overloading a binary operator where your type need to be the right-hand operand; for example operator<<(ostream&, my_type const &).
Overloading a binary operator where you want the left-hand side to be convertible to your type; for example, if your class is constructible from int, then 5 + my_type will work if you define a non-member operator+(my_type const&, my_type const&);, but not if you define a member my_type::operator+(my_type const &) const;.
Whether any of these needs to be friends depends on whether they can do their job using the class's public interface; for example, you could add a public print(ostream&) member that operator<< could use, and a public operator+= member that operator+ could use.
As an example of implementing operator+ in terms of operator+=:
my_type & my_type::operator+=(my_type const & rhs)
{
// do addition here
return *this;
}
// The first operand is passed by value, giving a modifiable copy
my_type operator+(my_type lhs, my_type const & rhs)
{
return lhs += rhs;
}
The simplest use case would probably be when overloading the stream output operator for a custom class.
For example, take a look at the following code (shamelessly copied from here). In this case the use of friend allows the non-class method to access the private fields of class, thus preventing the need to code several get methods (which otherwise you might not even want to create).
#include <iostream>
#include <cstring>
using namespace std;
class MyClass {
// now private
char name[80];
int areacode;
int prefix;
int num;
public:
MyClass(char *n, int a, int p, int nm)
{
strcpy(name, n);
areacode = a;
prefix = p;
num = nm;
}
friend ostream &operator<<(ostream &stream, MyClass o);
};
ostream &operator<<(ostream &stream, MyClass o)
{
stream << o.name << " ";
stream << "(" << o.areacode << ") ";
stream << o.prefix << "-" << o.num << "\n";
return stream;
}
int main() {
MyClass a("T", 1, 5, 1);
MyClass b("A", 3, 5, 5);
MyClass c("T", 2, 5, 9);
cout << a << b << c;
return 0;
}