Overloading fstream << operator to save "any" kind of data - c++

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) {

Related

Global overload of operator<< does not work, why?

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;
}

Friend ostream can't access private member

I have seen other questions like this but I didn't get a solution.
Here is the code:
cout_overload.h:
#ifndef COUT_OVERLOAD_H_
#define COUT_OVERLOAD_H_
#include <iostream>
class A
{
private:
int data;
public:
A(int d);
friend std::ostream & operator <<
(std::ostream os, const A &t );
};
#endif
cout_overload_r.cpp:
#include <iostream>
#include "cout_overload.h"
A::A(int d)
{
data = d;
}
std::ostream &operator << (std::ostream &os, const A&t)
{
os << " t = " << t.data ;
return os;
}
main.cpp:
#include <iostream> #include "cout_overload.h"
int main(void)
{
A ra(1);
using std::cout;
// cout<<ra;
return 0;
}
the error during compiling:
You need to modify your friend function and Use ostream& inside the
friend std::ostream & operator << (std::ostream os, const A &t );
And replace your above line,
friend std::ostream & operator << (std::ostream &os, const A &t );
Because ostream is an output stream, the & is to pass by reference ( the only way to pass streams to functions )..

c++ operator << for typedef within class

I plan to use overloaded operators in a c++ class but not as member functions. The problem is that the operators should not work on the data type defined by the class itself rather on typedefs defined within the class.
An excerpt of my code is as follows:
The class definition in the header file:
namespace myspace
{
class Exporter{
public:
Exporter(const Markov & MP);
Exporter(const Network & net);
~Exporter();
void Export(std::string filename);
typedef std::vector<int> pvi;
typedef std::vector<std::string> pvs;
protected:
void Export1(std::string filename, pvs Mydata);
void Export2(std::string filename, pvi Mydata2);
// Helper functions
friend std::ostream& operator<<(std::ostream&, const pvi& vi);
friend std::ostream& operator<<(std::ostream&, const pvs& vi);
...
private:
pvs Data1;
pvi Data2;
...
};
}
The implementation in a cpp file:
using namespace myspace;
//===============================================================================
std::ostream& operator<<(std::ostream& os, const Exporter::pvi& vi)
{
os << "(";
std::copy(vi.begin(), vi.end()-1, std::ostream_iterator<int>(os, ","));
std::copy(vi.end()-1, vi.end(), std::ostream_iterator<int>(os));
os << ")";
return os;
}
//===============================================================================
std::ostream& operator<<(std::ostream& os, const Exporter::pvs& vi)
{
os << "(";
std::copy(vi.begin(), vi.end()-1, std::ostream_iterator<std::string>(os, ","));
std::copy(vi.end()-1, vi.end(), std::ostream_iterator<std::string>(os));
os << ")";
return os;
}
//===============================================================================
void Exporter::Export(std::string filename)
{
Export1(std::string filename, Data1);
Export2(std::string filename, Data2);
}
//==============================================================================
void Exporter::Exporter1(std::string filename,pvs Mydata_s)
{
std::ofstream outf;
outf.open(filename.c_str());
outf << Mydata_s << "\n";
outf.close();
}
//==============================================================================
void Exporter::Exporter2(std::string filename,pvi Mydata_i)
{
std::ofstream outf;
outf.open(filename.c_str());
outf << Mydata_i << "\n";
outf.close();
}
//==============================================================================
During compilation no warnings and errors referring the operators are generated. But the output doesn't seems to be formated thus it looks like that the standard / default operators are used.
Are there any hints or suggestions how to overcome that?

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 Insertion Operator in C++

I have a class in which I'm trying to overload the << operator. For some reason, it is not being overloaded.
Here is my .h file:
friend std::ostream& operator<<(std::ostream&, const course &); //course is my class object name
in my .cpp, I have this as my implementation:
std::ostream& operator<<(std::ostream &out, const course & rhs){
out << rhs.info;
return out;
}
This should be correct, but when I try to compile it, it says that cout << tmp; is not defined in ostream.
I've included iostream in my .cpp and .h
I'm been pulling my hair out trying to figure this out. Can you see anything that's wrong with this?
EDIT:
Since what I'm doing seems to be correct, here's all of my source code: http://pastebin.com/f5b523770
line 46 is my prototype
line 377 is the implementation
line 435 is where it fails when i attempt to compile it.
also, I just tried compiling it on another machine, and it gives this error instead:
course.cpp:246: error: non-member function 'std::ostream& operator<<(std::ostream&, const course&)' cannot have cv-qualifier
make: *** [course.o] Error 1
The syntax you've listed is correct, but the overloaded operator prototype has to be declared in the course definition to work properly.
course.h
class course {
public:
friend std::ostream& operator<<(std::ostream&, const course&);
private:
int info;
}
course.cpp
std::ostream& operator<<(std::ostream &out, const course &rhs){
out << rhs.info;
return out;
}
It looks fine to me. Here's my version of it:
course.h
#include <iostream>
class course
{
public:
friend std::ostream& operator<<(std::ostream&, const course &); //course is my class object name
int info;
course(){info = 10;}
};
course.cpp
#include <iostream>
#include "course.h"
std::ostream& operator<<(std::ostream &out, const course & rhs)
{
out << rhs.info;
return out;
}
main_file.cpp
#include <iostream>
#include "course.h"
int main()
{
course a;
std::cout<<a;
return 0;
}
You should include the rest of the code, I don't think we can see where the problem is.
The following trivial example works:
class course
{
public:
course(int info) : info(info) { }
int info;
friend std::ostream& operator<<(std::ostream&, const course &);
};
std::ostream& operator<<(std::ostream &out, const course & rhs)
{
out << rhs.info;
return out;
}
int main(int, char*[])
{
course tmp(3);
std::cout << tmp;
return 0;
}
I found this helpful!
My insertion and extraction operators are slightly different.
here they are defined:
friend ostream& operator<<(ostream &fout, datatype toPrint)
friend istream& operator>>(istream &fin, datatype &toReadTo)
the syntax needs to be exact.