Global overload of operator<< does not work, why? - c++

I have learnt the operator<< can be overloaded by making it a friend function of class.
For example,
struct Test
{
std::string d_data;
Test(const std::string & data) : d_data{data} {}
friend std::ostream & operator<<(std::ostream & ostr, const Test & obj)
{
ostr << obj.d_data << '\n';
return ostr;
}
};
int main()
{
Test t1("one");
std::cout << t1;
Test t2("two");
std::cout << t2;
}
one
two
This seems to work as expected.
But, I'm unable to understand why the same isn't working for a global overload.
#include <iostream>
#include <ostream>
#include <string>
std::ostream & operator<<(std::ostream & os, const std::string & s)
{
os << s << '\n';
return os;
}
int main()
{
std::cout << "stackoverflow";
std::cout << "stackoverflow";
}
stackoverflowstackoverflow
Expected the strings to be separated by a newline, but didn't work as expected.

Your operator using
std::cout << "stackoverflow";
requires a user-defined conversion from an object of the type const char * (after the implicit conversion of the string literal to pointer to its first character) to an object of the type std::string.
However the standard basic_ostream class has already an operator that does not require such a conversion
template<class charT, class traits>
basic_ostream<charT, traits>& operator<<(basic_ostream<charT, traits>&, const char*);
So this operator is called instead of your operator.
Moreover within your operator
std::ostream & operator<<(std::ostream & os, const std::string & s)
{
os << s << '\n';
return os;
}
there is recursive calls of itself.
Your could define your operator the following way
#include <iostream>
#include <string>
std::ostream & operator<<(std::ostream & os, const char *s)
{
return std::operator <<( os, s ) << '\n';
}
int main()
{
std::cout << "stackoverflow";
std::cout << "stackoverflow";
}
and get the expected result
stackoverflow
stackoverflow

Note that "stackoverflow" is of type const char[], but not std::string. That means your overload won't be invoked, but the one from standard library (operator<<(std::basic_ostream) is invoked, because it's an exact match and doesn't require the implicit conversion from const char[] to std::string.
template< class Traits >
basic_ostream<char,Traits>& operator<<( basic_ostream<char,Traits>& os,
const char* s );
BTW: It could be found because of ADL.

You can overload globally, but "stackoverflow" is not a std::string, so yours isn't used.
(And there already is such an overload in the standard library.)
To see that it works, move your first overload out of the class definition and make it a non-friend.
The only reason it has to be declared friend is that you have declared it inside the class definition, so it would be a member function otherwise.
This will work as you expect:
struct Test
{
std::string d_data;
Test(const std::string & data) : d_data{data} {}
};
std::ostream & operator<<(std::ostream & ostr, const Test & obj)
{
ostr << obj.d_data << '\n';
return ostr;
}
int main()
{
Test t1("one");
std::cout << t1;
Test t2("two");
std::cout << t2;
}

Related

How do I properly overload the operator in this specific case using C++

I am new to C++ programming and am having trouble implementing this operator overloading. It gives the error that no operator "<<" matches these operands.
class class1{
public:
bool operator==(class1 &);
friend ostream & operator<<(ostream &, class1 &);
private:
string name;
};
/*Friend ostream & operator <<*/
ostream & operator << (ostream & os, class1 & obj){
os << obj.name;
return os;
}
Someone mentioned I need another overloaded operator, but I can't figure out how to make it work with another overloaded operator
Here is the situation with your code; you have a private member string variable within your class where no outside object can set this variable. Your class does not contain a defined constructor nor a setting method. When I tried your code I had to change your operator declaration and definition from this:
std::ostream& operator<<( std::ostream& os, class1& obj );
to this:
std::ostream& operator<<( std::ostream& os, const class1& obj );
in order for it to compile. However when it came to building the project I was getting a Linker Error of an unresolved identifier. What was happening here is that the ostream object that you are declaring as a friend to your class object does know about the private member string but it can not do anything with it since this string is empty or not valid. I changed your class to this:
#include <conio.h>
#include <string>
#include <iostream>
class class1 {
friend std::ostream& operator<<( std::ostream& out, const class1& other );
private:
std::string m_strName;
public:
explicit class1( std::string& strName ) : m_strName( strName ) {}
void setName( std::string& strName ) { m_strName = strName; }
std::string getName() const { return m_strName; }
};
std::ostream& operator << ( std::ostream& out, class1& obj ) {
out << obj.m_strName << std::endl;
// out << obj.getName() << std::endl;
return out;
}
int main() {
class1 a( std::string( "class1" ) );
std::cout << a << std::endl;
std::cout << "Press any key to quit" << std::endl;
_getch();
return 0;
}
This compiles, builds, links and executes properly and displays appropriate text and exits with a value of 0 for no errors. I am using MSV2013 on a Win7 machine. The main issue was that since your class had no way to populate its string member upon construction the ostream operator object could not resolve the variable in use.
The overload operator<<(std::ostream&, std::string) is actually defined by #include <string>.
Although std::string is also defined by that header, it is still possible for std::string to be defined but not this operator overload, if you did not include that header.
The C++ standard requires that certain headers provide certain features, but it does not prohibit that feature also being provided by another header. In your case, the compiler/library writer has decided that implementing some other feature in another header was most easily done by defining std::string, but it would have done this by having a separate file defining std::string which is included both by <string> and by the other header.
remove the keyword "friend" for ostream if you intent for it to be a public member. If your want ostream to be friend move it above public:
operator== should have two const parameter, const if you do not intend to change.
friend ostream & operator<<(ostream &, const class1 &);
public:
bool operator==(const class1& x, const class1& y);
or
public:
bool operator==(const class1& x, const class1& y);
ostream & operator<<(ostream &, const class1 &);
make operator << second parameter a const might help
ostream & operator << (ostream & os, const class1 & obj){
os << obj.name;
return os;
}

Overloading fstream << operator to save "any" kind of data

I have created a Test class that has a public variable double x. I have overloaded the ostream << operater to be able to print out the variable x. I have also written an external save(filename, object) function that would save the content of the object in a particular way. I would like to use the << operator to save the content of x into a file.
Header file (TestH.hpp) looks like this:
#ifndef TESTH_HPP_
#define TESTH_HPP_
#include <iostream>
#include <fstream>
#include <string>
class Test {
public:
double x;
friend std::ostream& operator << (std::ostream& os, Test& p);
inline Test();
inline virtual ~Test();
};
inline std::ostream& operator << (std::ostream& os, Test& p);
template <class V>
inline void save(const std::string& pname, const V& data);
#endif /* TESTH_HPP_ */
This is the file for defining the functions (TestC.cpp):
#ifndef TESTC_CPP_
#define TESTC_CPP_
#include "TestH.hpp"
Test::Test() {
x=10;
}
Test::~Test() {}
std::ostream& operator << (std::ostream& os, Test& p) {
// Output to screen
os << "Test:\t";
os << p.x;
return os;
}
template <class V>
void save(const std::string& pname, const V& data) {
std::ofstream myfile;
myfile.open(pname.c_str());
myfile << data;
myfile.close();
std::cout << "====== File is saved! ======\nPathname: " << pname << std::endl;
}
#endif /* TESTC_CPP_ */
And finally here is the code to test the save function (Test.cpp):
#include <iostream>
#include "TestC.cpp"
int main () {
std::string fn = "test.txt";
int i=1;
Test a;
// std::cout << a;
save(fn,a);
return 0;
}
I get a really long list of errors, but basically it sais that in the TestC.cpp code the compiler cannot do the myfile << data; command:
In file included from ../Test.cpp:3:0:
../TestC.cpp:33:9: note: ‘const Test’ is not derived from ‘const std::basic_string<_CharT, _Traits, _Alloc>’
myfile << data;
Could you please help me resolving this issue. Thank you for your time.
You are streaming Test by non-const reference:
friend std::ostream& operator << (std::ostream& os, Test& p);
You want to stream it by const reference:
friend std::ostream& operator << (std::ostream& os, const Test& p);
^^^^^^
The error comes from the fact that when you call it from save(), you are passing in a const reference:
template <class V>
void save(const std::string& pname, const V& data) {
...
myfile << data; // <== data is const Test&
...
}
You get the error because you are trying to save a const object and you have overloaded the operator for non const case.
Turn
std::ostream& operator << (std::ostream& os, Test& p) {
into
std::ostream& operator << (std::ostream& os, const Test& p) {

Storing values in a container

I'm trying to read two values from a file and store them in my class called God. God has two data members, name and mythology. I wish to store the values in a list<God> (the god and its respective mythology) and then print them out. Here is my code so far:
#include <iostream>
#include <fstream>
#include <list>
#include <string>
using namespace std;
class God {
string name;
string mythology;
public:
God(string& a, string& b) {
name=a;
mythology =b;
}
friend ostream& operator<<( ostream& os,const God&);
};
void read_gods(list<God>& s) {
string gname, gmyth;
//reading values from file
ifstream inFile;
inFile.open("gods.txt");
while(!inFile.eof()) {
inFile >> gname >> gmyth ;
s.push_back(God(gname, gmyth));
}
}
ostream& operator<<( ostream& os,const God& god) {
return os << god.name << god.mythology;
}
int main() {
//container:
list<God> Godmyth;
read_gods(Godmyth);
cout << Godmyth;
return 0;
}
If for example I read in Zeus, Greek then how would I be able to access them?
The error I'm receiving is:
error: cannot bind 'std::ostream {aka std::basic_ostream<char>}' lvalue to 'std::basic_ostream<char>&&'|
You should write either operator << or some member function for class God that outputs its data members.
For example
class God
{
public:
std::ostream & out( std::ostream &os ) const
{
return os << name << ": " << mythology;
}
//...
};
Or
class God
{
public:
friend std::ostream & operator <<( std::ostream &, const God & );
//...
};
std::ostream & operator <<( std::ostream &os, const God &god )
{
return os << god.name << ": " << god.mythology;
}
In this case instead of invalid statement
cout << Godmyth << endl;
you could write
for ( const God &god : Godmyth ) std::cout << god << std::endl;
Or if you simply want to access the data members then you should write getters.
For example
class God
{
public:
std::string GetName() const { return name; }
std::string GetMythology() const { return mythology; }
//...
There is no overloaded operator<< allowing printing std::list's content using std::cout.
What you can do?
As #Vlad mentioned, you can write
for ( const God &god : Godmyth )
std::cout << god << '\n';
Alternatively, you can write your own operator<<:
template<typename T>
std::ostream& operator<< (std::ostream &os, const std::list<T> &_list){
os << "[\n";
for ( const auto &item : _list )
os << item << ";\n";
return os << ']';
}

no return statement in friend class

The warning is being generated by the ostream & operator<<(ostream &os, A &A0) function.
Here's how the class's defined:
class A
{
public:
friend ostream & operator<<(ostream &os, A &A0);
A& operator=(string strSlot_);
A& operator+(string strSlot_);
A& operator+(const A &B);
A& operator=(const A &B);
string slotReturn();
A(string strSlot_);
A(const A &object);
void slotChange();
void sCout();
~A();
A();
private:
string strSlot;
int n;
};
ostream & operator<<(ostream &os, A &A0)
{
os << "strSlot = \"" << A0.slotReturn() << "\"" << endl;
}
string A::slotReturn()
{
return strSlot;
}
The question is, what is it supposed to return? *this doesn't seem to work (because it's a friend?). (It's merely a warning, but still, I just want to know.)
Also, why can't I pass A &A0 as a const (in which case the error is: "passing 'const A' as 'this' argument of 'std::string A::slotReturn()' discards qualifiers")?
You need to return the std::ostream& itself:
ostream & operator<<(ostream &os, A &A0)
{
return os << "strSlot = \"" << A0.slotReturn() << "\"" << endl;
}
As an aside, the terminology is slightly off. There is no "friend class". The std::ostream& operator<< is the friend here. But it doesn't even need to be a friend, because it just calls a public member function of A. So you can remove the friend declaration.
You should probably also make slotReturn() a const method:
string slotReturn() const;
// ^ const method
and modify the ostream& operator<< to take a const reference:
ostream & operator<<(ostream& os, const A& A0) { .... }
This will allow you to print out temporaries:
std::cout << A("I am a temporary!") << "\n";

Overloading I/O operator C++

I'm trying to overload the << operator. I'm expecting the output to be InitializingHello WorldOut but it is just outputting Hello World. I can't figure out what is wrong with my code. Thanks for your help.
#include <iostream>
using namespace std;
ostream &operator << (ostream &out, const char* &s)
{
out << "Initializing" << s << "Out";
return out;
}
void main() {
cout << "Hello World" << endl;
system("Pause");
}
"Hello World" is actually of type const char[12], which can decay into an r-value (temporary) of type const char *, but your function takes a reference to a const char*, and as you may know, you cannot bind a reference to a non-const r-value. So your operator is not called, but instead the standard ostream &operator << (ostream &out, const char* s) is.
PS. Please do not write void main(). It should be int main() unless you are in an embedded system (not likely).
There already is an overload for << with the exact same prototype. The compiler cannot decide which to use...
There is already a operator<< for const char* defined in the standard library, which is used in the output. Your overload is not used because the temporary string literal cannot be bound to the non-const reference in the operators second parameter.
If you remove the reference or make it const, then your operator is called. It doesn't even conflict with the one in your standard library, since that one is implemented as a function template. Yours is not, and non-templated functions are preferred by the compiler.
If it is then called, it leads to a stack overflow because out << "Initializing" immediately calls the same operator again recursively.
rodrigo pointed out that the type of a string literal is const char[x], and I had an evil idea:
#include <iostream>
using namespace std;
template<int len>
ostream &operator << (ostream &out, const char (&s)[len])
{
out << ((const char*)"Initializing") << ((const char*)s) << ((const char*)"Out");
return out;
}
int main() {
cout << "Hello World" << endl;
}
http://ideone.com/7wCNy
I think that since the left hand side is in the std namespace, it's using the function ostream& std::operator << (ostream &out, const char* s) that's defined in the std namespace instead of yours in the global namespace. If you were to try to put yours into the std namespace, you'd get a linker error. Your only real hope is to change the types of one side or the other, probably by making a wrapper around them.
struct charptr {
const char* ptr;
charptr(const char* p) :ptr(p) {}
};
ostream &operator << (ostream &out, const charptr &s)
{
out << "Initializing" << s.ptr << "Out";
return out;
}
int main() { //int main, not void
cout << charptr("Hello World") << endl;
system("Pause");
}