Friend ostream can't access private member - c++

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

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 function still can't access private member

I have a simple C++ class, which I'm trying to add stream operators to, so it can be used with cout and cin
#include <iostream>
namespace testing_namespace {
class test {
friend std::ostream &operator<<(std::ostream &os, const test &o);
friend std::istream &operator>>(std::istream &is, test &o);
public:
void doThing();
private:
int member;
};
}
This is the implementation file:
std::ostream &operator<<(std::ostream &os, const testing_namespace::test &o) {
return os << o.member;
}
std::istream &operator>>(std::istream &is, testing_namespace::test &o) {
return is >> o.member;
}
void testing_namespace::test::doThing() {
std::cout << member << " thing" << std::endl;
}
I'm getting an error on compilation:
In function 'std::ostream& operator<<(std::ostream&, const testing_namespace::test&)':
test.cpp:8:20: error: 'int testing_namespace::test::member' is private within this context
return os << o.member;
with a similar error for operator>>. The doThing method compiles with no issues.
I'm not sure what I'm missing here - shouldn't friend functions be able to access the private members of the class test?
You need to define those functions under the namespace too. When you do that, you can omit the name of the namespace from test.
namespace testing_namespace
{
std::ostream &operator<<(std::ostream &os, const test &o) {
return os << o.member;
}
std::istream &operator>>(std::istream &is, test &o) {
return is >> o.member;
}
}

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

error: declaration of 'operator<<' as non-function|

I am having a really hard time with overloading the << operator. I am working on a homework assignment where I can only modify certain portions of the code. Before you ask, I AM stuck using a struct instead of a class. Here are the portions of the affected code:
The calling function is:
/*
* Write a CSV report listing each course and its enrollment.
*/
void generateReport (ostream& reportFile,
int numCourses,
Course* courses)
{
for (int i = 0; i < numCourses; ++i)
{
//courses is an array of "Course" structs
reportFile << courses[i] << endl;
}
}
Here is the .h file:
#ifndef COURSE_H
#define COURSE_H
#include <iostream>
#include <string>
struct Course {
std::string name;
int maxEnrollment;
int enrollment;
Course();
Course(std::string cName);
std::ostream& operator << (ostream &out, const Course &c);
};
#endif
Here is the .cpp file:
#include "course.h"
using namespace std;
Course::Course()
{
name = "";
maxEnrollment = 0;
enrollment = 0;
}
Course::Course(string cName)
{
name = cName;
maxEnrollment = 0;
enrollment = 0;
}
// send course to file
ostream& Course::operator << (ostream &out, const Course &c)
{
out << c.name << "," << c.enrollment << endl;
return out;
}
Here is the error message I keep getting:
error: declaration of 'operator<<' as non-function|
I have been searching the internet for hours and tried lots of different approaches to solve this problem with no success.
Please help!!
I tried a couple of different methods to fix this based on advice. Here are two methods I tried which did not work:
Method 1:
#ifndef COURSE_H
#define COURSE_H
#include <iostream>
#include <string>
struct Course {
std::string name;
int maxEnrollment;
int enrollment;
Course();
Course(std::string cName);
};
//Moved this outside the struct
std::ostream& operator << (ostream &out, const Course &c);
#endif
Method 2 (also failed to change error):
#include "course.h"
using namespace std;
Course::Course()
{
name = "";
maxEnrollment = 0;
enrollment = 0;
}
Course::Course(string cName)
{
name = cName;
maxEnrollment = 0;
enrollment = 0;
}
std::ostream& operator << (ostream &out, const Course &c);
// send course to file
ostream& Course::operator << (ostream &out, const Course &c)
{
out << c.name << "," << c.enrollment << endl;
return out;
}
RE-EDIT--------------------------------------------------------
After some of the comments and help, here is my current code:
In the .h file:
#ifndef COURSE_H
#define COURSE_H
#include <iostream>
#include <string>
struct Course {
std::string name;
int maxEnrollment;
int enrollment;
Course();
Course(std::string cName);
std::ostream& operator << (std::ostream &out, const Course &c);
};
#endif
In the .cpp file:
#include "course.h"
using namespace std;
Course::Course()
{
name = "";
maxEnrollment = 0;
enrollment = 0;
}
Course::Course(string cName)
{
name = cName;
maxEnrollment = 0;
enrollment = 0;
}
// send course to file
ostream& operator << (ostream &out, const Course &c)
{
out << c.name << "," << c.enrollment << endl;
return out;
}
You forgot to include <ostream> and the namespace specifier std:: in your argument, which leads into your error.
Read on if you want to hear about your next error:
std::ostream& operator << (std::ostream &out, const Course &c);
This means that you define an operator which should work on a current instance of a Course as left hand side (*this), since it is defined as a member. This would lead into an operator that has one left hand side and two right hand sides, which isn't possible.
You need to define the operator as a non-member function, since the left hand side should be an ostream& and not Course&.
std::ostream& operator << (std::ostream &out, const Course &c);
should be
friend std::ostream& operator << (std::ostream &out, const Course &c);
And
std::ostream& Course::operator << (std::ostream &out, const Course &c) // Not a member of Course
{
should be
std::ostream& operator << (std::ostream &out, const Course &c)
{
Since it is not a member of Course.
std::ostream& operator << (ostream &out, const Course &c); inside the Course declaration, must be declared as friend, otherwise it cannot take two parameters.
also, the fist parameter must be std::ostream& and not just ostream&