The following example is my demo. At first, I create an abstract class named Expr_node. After that I create another class Int_node. In order to access the private and protected member function normally, I set the Expr class as the friend class of Expr_node. However, I still cannot access to the print function by overload the operator<<.
#include <iostream>
#include <string>
#include <utility>
using namespace std;
class Expr_node;
class Int_node;
class Expr {
friend ostream& operator<<(ostream&, const Expr&);
Expr_node* p;
public:
Expr(int);
Expr(const string&, const Expr&);
Expr(const string&, const Expr&, const Expr&);
Expr(const Expr& t);
Expr& operator=(const Expr&);
};
class Expr_node {
friend ostream& operator<< (ostream&, const Expr_node&);
friend class Expr;
int use;
protected:
Expr_node(): use(1) {}
virtual ~Expr_node() = default;
virtual void print(ostream&) const = 0;
};
ostream& operator<< (ostream& o, const Expr_node& e) {
e.print(o);
return o;
}
ostream& operator<< (ostream& o, const Expr& e) {
e.p->print(o);
return o;
}
class Int_node: public Expr_node {
friend class Expr;
int n;
explicit Int_node(int k) : n(k) {}
void print(ostream& o) const override { o << n;}
};
It's the problem of operator<<. It's not class member, but friend function. Implement function inside Expr class, which call print on p. Then call it on Expr parameter.
Something like this:
#include <iostream>
#include <string>
#include <utility>
using namespace std;
class Expr_node;
class Int_node;
class Expr {
friend ostream& operator<<(ostream&, const Expr&);
Expr_node* p;
public:
Expr(int);
Expr(const string&, const Expr&);
Expr(const string&, const Expr&, const Expr&);
Expr(const Expr& t);
Expr& operator=(const Expr&);
void print(ostream& o) const
{
this->p->print(o);
}
};
class Expr_node {
friend ostream& operator<< (ostream&, const Expr_node&);
friend class Expr;
int use;
protected:
Expr_node(): use(1) {}
virtual ~Expr_node() = default;
virtual void print(ostream&) const = 0;
};
ostream& operator<< (ostream& o, const Expr_node& e) {
e.print(o);
return o;
}
ostream& operator<< (ostream& o, const Expr& e) {
e.print(o);
return o;
}
Related
I want to implemnent an operator<< for streaming my class (say it's named Paragraph). Class Paragraph has some private data, for which reason I want the (freestanding) operator<< function to be a friend. So, I do as suggested, e.g., here on SO. friend statement, implement the operator<< and all is well.
But now I want to put Paragraph inside a namespace, say namespace foo. It no longer works! If I write:
namespace foo {
class Paragraph {
public:
explicit Paragraph(std::string const& init) :m_para(init) {}
std::string const& to_str() const { return m_para; }
private:
friend std::ostream & operator<<(std::ostream &os, const Paragraph& p);
std::string m_para;
};
} // namespace foo
The compiler tells me I've befriended foo::operator<<, not ::operator<<. Ok, fair enough. So, I replace the friend line with:
friend std::ostream & ::operator<<(std::ostream &os, const Paragraph& p);
but I get an error again (from GCC 5.4.0), telling me the ::operator<< has not having been declared. Ok, let's declare it then. Will this work?:
namespace foo {
std::ostream & ::operator<<(std::ostream &os, const foo::Paragraph& p);
class Paragraph {
public:
explicit Paragraph(std::string const& init) :m_para(init) {}
std::string const& to_str() const { return m_para; }
private:
friend std::ostream & operator<<(std::ostream &os, const Paragraph& p);
std::string m_para;
};
} // namespace foo
Nope, it doesn't know about Paragraph when reading the declaration of ::operator<. Ok, let's forward-declare:
namespace foo {
class Paragraph;
std::ostream & ::operator<<(std::ostream &os, const foo::Paragraph& p);
class Paragraph { /* actual definition here */ } }
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p) { /* impl */ }
no luck. I get the weird error:
f.cpp:23:16: note: candidate: std::ostream& operator<<(std::ostream&, const foo::Paragraph&)
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p)
^
f.cpp:11:15: note: candidate: std::ostream& operator<<(std::ostream&, const foo::Paragraph&)
std::ostream& ::operator<<(std::ostream &os, const foo::Paragraph& p);
... and here I was thinking the global namespace and the :: namespace are the same thing... arent' they? (sigh). No matter, let's move the declaration out of the namespace:
class foo::Paragraph;
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p);
namespace foo { class Paragraph { /* actual definition here */ } }
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p) { /* impl */ }
Still not good enough, now I get the "'foo' has not been declared" error. (granshes teeth) fine! Be that way!
namespace foo { class Paragraph; }
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p);
namespace foo { class Paragraph { /* actual definition here */ } }
std::ostream & operator<<(std::ostream &os, const foo::Paragraph& p) { /* impl */ }
so this, but no less than this, works. That's terrible! Surely there must be some kind of less verbose way to do it... right?
Note: Assume the operator<< can't be inlined and must be defined separately.
It seems your problem stems from not realizing how ADL can find the right operator<< as long as it is the same namespace as Paragraph. To expand on your first example
// this is what you have already
namespace foo {
class Paragraph {
public:
explicit Paragraph(std::string const& init) :m_para(init) {}
std::string const& to_str() const { return m_para; }
private:
friend std::ostream & operator<<(std::ostream &os, const Paragraph& p);
std::string m_para;
};
} // namespace foo
// Now we can add a definition here, or in a different TU
namespace foo {
std::ostream& operator<<(std::ostream& os, const Paragraph& p) {
return os << p.m_para;
}
} // namespace foo
int main() {
foo::Paragraph p("hello");
// finds your operator<< using adl
std::cout << p << '\n';
}
Just put the definition of the << operator in the namespace along with Paragraph. Argument-dependent lookup will find it when you insert a Paragraph object into a stream.
// myheader.h:
namespace ns {
struct x {
/* ... */
friend std::ostream& operator<<(std::ostream&, const x&);
};
}
// myheader.cpp:
#include "myheader.h"
namespace ns {
std::ostream& operator<<(std::ostream& os, const x& xx) {
os << xx.whatever() << '\n';
return os;
}
}
Or, if it's small enough to warrant inlining, just do that:
// myheader.h:
namespace ns {
struct x {
/* ... */
friend std::ostream& operator<<(std::ostream&, const x&);
};
inline std::ostream& operator<<(std::ostream& os, const x& xx) {
os << xx.whatever() << '\n';
return os;
}
}
Consider the following example:
class SIP{
public:
friend std::ostream& operator<<(std::ostream& os, const SIP& c);
private:
class BusStop;
std::vector<BusStop*> mbusStops;
};
class SIP::BusStop{
private:
struct BusInfo;
std::vector<BusInfo*> mbusStopTerminal;
};
struct SIP::BusStop::BusInfo{
std::string from;
std::string to;
};
std::ostream& operator<<(std::ostream &os, const SIP &c) {
for (std::vector<SIP::BusStop*>::const_iterator it = c.mbusStops.begin();
it != c.mbusStops.end(); it++){
for (std::vector<SIP::BusStop::BusInfo*>::const_iterator it2 = mbusStopTerminal.begin();
it2 != mbusStopTerminal.end(); it2++){
}
}
return os;
}
It won't compile, because the BusInfo struct is private. Friend classes can't access private members of nested classes by default. What should I do in that situation? Is there any workaround?
You could add a stop-printing function to SIP:
class SIP{
public:
friend std::ostream& operator<<(std::ostream& os, const SIP& c);
private:
void printStops(std::ostream& os);
class BusStop;
std::vector<BusStop*> mbusStops;
};
std::ostream& operator<<(std::ostream &os, const SIP &c) {
c.printStops(os);
return os;
}
or you could just add operators all the way down:
class SIP{
public:
friend std::ostream& operator<<(std::ostream& os, const SIP& c);
private:
class BusStop;
std::vector<BusStop*> mbusStops;
};
class SIP::BusStop{
private:
friend std::ostream& operator<<(std::ostream& os, const BusStop& c);
struct BusInfo;
std::vector<BusInfo*> mbusStopTerminal;
};
struct SIP::BusStop::BusInfo{
std::string from;
std::string to;
};
std::ostream& operator<<(std::ostream &os, const SIP::BusStop::BusInfo &i)
{
// Whatever
}
std::ostream& operator<<(std::ostream &os, const SIP::BusStop &c)
{
for (std::vector<SIP::BusStop::BusInfo*>::const_iterator it = mbusStopTerminal.begin();
it != mbusStopTerminal.end(); it++){
os << **it;
}
}
std::ostream& operator<<(std::ostream &os, const SIP &c) {
for (std::vector<SIP::BusStop*>::const_iterator it = c.mbusStops.begin();
it != c.mbusStops.end(); it++){
os << **it;
}
return os;
}
or any combination of approaches that suits your code.
Hello dear StackOverflowers!
I am having trouble with a template structure which comprises another (but non-template) structure.
Here's the thing:
Structure B is non-template and is defined inside a template structure A.
Strcure B is "protected" because it exists only for the purposes of structure A and no-one and nothing else shall use it outside of structure A.
There's an overload of operator<< for structure B, so that objects of type B can be sent to the standard output "cout << B_type_object;" (and it's A's friend so that it can access B which is protected).
The aforementioned printing of B objects is done only by methods defined in A (because of "2.").
As long as both structures are non-template everything works like a charm.
The moment A is a template I get an error message (provided in the code section).
Here is the working code (where A is not template):
#include <iostream>
#include <string>
struct A
{
protected:
struct B
{
std::string something;
B& operator= (const std::string&& rhs)
{
this->something = std::move(rhs);
return *this;
}
};
B B_object;
friend std::ostream& operator<< (std::ostream& output, const typename A::B& ob);
public:
void method ()
{
B_object = "This is text.";
//No error here
std::cout << B_object;
}
};
std::ostream& operator<< (std::ostream& output, const typename A::B& ob)
{
output << ob.something;
return output;
}
int main(int argc, const char * argv[])
{
A obj;
obj.method();
return 0;
}
This is the code which doesn't work
#include <iostream>
#include <string>
template <typename T>
struct A
{
T variable;
protected:
struct B
{
std::string something;
B& operator= (const std::string&& rhs)
{
this->something = std::move(rhs);
return *this;
}
};
B B_object;
template <typename X> friend std::ostream& operator<< (std::ostream& output, typename A/*<X>*/::B& ob);
public:
void method ()
{
B_object = "This is text.";
//ERROR: Invalid operands to binary expression ('ostream' (aka 'basic_ostream<char>') and 'A<int>::B')
std::cout << B_object;
}
};
template <typename X>
std::ostream& operator<< (std::ostream& output, typename A<X>::B& ob)
{
output << ob.something;
return output;
}
int main(int argc, const char * argv[])
{
A<int> obj;
obj.method();
return 0;
}
Just declare the operator inline in B, then it works:
...
struct B
{
std::string something;
B& operator= (const std::string&& rhs)
{
this->something = std::move(rhs);
return *this;
}
friend std::ostream& operator<< (std::ostream& output, const typename A<T>::B& ob)
{
output << ob.something;
return output;
}
};
...
This has also the advantage that your are not friending any operator<< of any A<X>. In your example, the operator taking A<string>::B would also be a friend of A<int>::B. For a more in-depth explanation, see this answer:
https://stackoverflow.com/a/4661372/36565
My current code is not working.
I am trying to use << operator of Person class in the << operator of Student class. Is that possible?
#include <iostream>
using namespace std;
class Person
{
private:
int EGN;
public:
Person(int e):EGN(e){}
friend ostream& operator <<(ostream& out, const Person& p);
};
ostream& operator <<(ostream& out, const Person& p)
{
out<<p.EGN<<endl;
return out;
}
class Student: public Person
{
private:
int fn;
public:
Student(int e, int f):Person(e)
{
fn=f;
}
friend ostream& operator <<(ostream& out, const Student& p);
};
ostream& operator <<(ostream& out, const Student& p)
{
Person :: operator << (out,p);
out<<p.fn<<endl;
return out;
}
Person's operator << is a friend, not a member, so you can't access it using the :: operator.
Try casting your student to a person to call the right overload:
out << static_cast<const Person &>(p);
Hi I have this ostream operator that gives me this error when I compile: cannot access private member declared in class 'CService'
here is my code:
friend ostream& operator <<(ostream& os, CService &obj);
ostream& operator<<(ostream &os, CService &obj) {
os<<obj.m_strClient;
return os;
}
I tried returning ostream& but that doesn't fix the problem, instead it adds another error syntax error : ';'
Here is my entire code:
#include <iostream>
#include <string>
#include <fstream>
#include <vector>
#include <algorithm>
using namespace std;
class CService {
private:
string m_strClient;
string m_strSeller;
int m_iMinutes;
public:
CService() {
m_strClient="N/A";
m_strSeller="N/A";
m_iMinutes=0;
}
CService( string c, string s, int m ) {
m_strClient=c;
m_strSeller=s;
m_iMinutes=m;
}
CService(const CService &obj ) {
m_strClient=obj.m_strClient;
m_strSeller=obj.m_strSeller;
m_iMinutes=obj.m_iMinutes;
}
string GetClient() {
return m_strClient;
}
string GetSeller() {
return m_strSeller;
}
int GetMusic() {
return m_iMinutes;
}
CService CService::operator =(CService obj) {
m_strClient=obj.m_strClient;
m_strSeller=obj.m_strSeller;
m_iMinutes=obj.m_iMinutes;
return *this;
}
bool operator < (const CService &obj) const {
return m_strSeller<obj.m_strSeller;
}
CService CService::operator +(const CService &obj) const {
return CService( m_iMinutes+obj.m_iMinutes );
}
friend ostream& operator <<(ostream& os, CService &obj);
bool CService::operator==(CService &obj) {
return (obj.m_strSeller==m_strSeller);
}
};
ostream& operator<<(ostream &os, CService &obj) {
os<<obj.m_strClient;
return ostream&;
}