wondering is there a way to access the private members while in overloaded operator without declaring 'friend' ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14
istream & operator >>( istream & input, Course & C )
{
input >> unitName >> unitId >> credits; // how should this part be?
return input;
}
ostream & operator <<( ostream & os, const Course & C )
{
os << " Course: " << C.getUnitName() << '\n'
<< " Section: " << C.getUnitId() << '\n'
<< " Credits: " << C.GetCredits() << '\n';
return os;
}
ive tried the following:
- searching the net for possible explanation but with no avail.
- using the ifstream to read in the object but other parts of my code gotten the 'no matching operator >>' error
there are lots of ugly ways to do this. Most of them are bad ideas that are only generally useful if you are stuck using a locked 3rd party library that is hiding things from you. They all generally end up being a version of "acquire a pointer to the offending item".
friending the I/O operators (and, actually, all of binary operators, as long as you also define them inside the class) is really the most appropriate way to define them in C++.
Why look for something else?
Hi guys, i know that using the 'friend' is the most effective solution for this problem. I think my lecturer is drilling us on using the getters/setters in the class to retrieve private members.
@OP Probably sounds like nagging but ... the point is friend is the way for another class to access a classes private members in a controlled and consistent way, consistent with data hiding principles.
It is more or less not consistent with the principles of C++ to use getters and setters even though it can be done albeit by over-complicating a simple method.
Maybe your lecturer doesn't understand what friend is all about.
the point is friend is the way for another class to access a classes private members in a controlled and consistent way, consistent with data hiding principles.
I suspect that the point the prof is trying to make is that you shouldn't provide access to private data unless it's necessary. If there are getter and setter functions available for everything that you need to print, then there's no need to make the << and >> operators friends.
The advantage of this comes when you want to change the private data. The fewer places that have access to it, the fewer places that you have to worry about.
I'll add my usual caveat: it's an interesting and valuable idea, but it adds certain complexity now, for a possible simplification in the future. Before doing it, one should weigh the chances of using the future simplification.
Sometimes (particularly in the case of overloaded binary operations), the non-member function is declared as an inline friend (even if it does not require any access to non-public members of the class). The advantage of doing this is that the function can't be found other than through ADL. This is ideal for overloaded operators (ie. it works as expected when used in as an operator, but it does not pollute the enclosing or associated namespaces, and it does not contribute to potential ambiguities in overload resolution).
AFAIK, this practice is currently limited to expert code; it hasn't entered mainstream C++ as yet.
I think this is what Cubbi meant when he said:
friending the I/O operators (and, actually, all of binary operators, as long as you also define them inside the class) is really the most appropriate way to define them in C++.
namespace A
{
struct B
{
int value() const { return v ; }
void value( int new_val ) { v = new_val ; }
private: int v = 23 ;
// foo is not visible except through ADL
friendint foo( B& b, int i ) { b.value( b.value() + i ) ; return b.value() ; }
};
// bar pollutes the enclosing namespace
int bar( B& b, int i ) { b.value( b.value() + i ) ; return b.value() ; }
}
int main()
{
A::B b ;
bar( b, 5 ) ; // fine: found via ADL
A::bar( b, 5 ) ; // fine: bar is a member of namespace A
auto p = &A::bar ; // fine: bar is a member of namespace A
foo( b, 5 ) ; // fine: found via ADL
A::foo( b, 5 ) ; // *** error: foo is not a member of namespace A
auto p2 = &A::foo ; // *** error: foo is not a member of namespace A
auto p3 = &A::B::foo ; // *** error: foo is not a member of A::B
auto p4 = &::foo ; // *** error: foo is not a member of the global namespace
// foo can be accessed only via ADL (aka koenig lookup).
}
friend declaration
C++
C++ language
Classes
The friend declaration appears in a class body and grants a function or another class access to private and protected members of the class where the friend declaration appears.
The point was not about the friend declaration being in the body of he class; that the friend declaration must appear in the body of the class is a syntanctic requirement.
The discussion is about the distinction between placing the definition of the friend function within the body of the class vs. placing it outside the body of the class.
It is required that the declaration of a friend must be inside the class body.
If it appears outside the class body, it is a syntax error.
It is not required that the definition of a friend function must appear inside the class body.
The definitions of a friend function can be outside the class body in a well-formed program.
#include <iostream>
struct B ;
struct A
{
explicit A( int v ) : v(v) {}
int value() const { return v ; }
private: int v ;
// friend declaration for operator+
// it is required that this declarations must appear within the body of he class
friend A operator+ ( A a1, A a2 ) ;
// friend declaration for operator-
// again, it is required that this declarations must appear within the body of the class
// however, for operator-, the definition also appears in the body of he class
friend A operator- ( A a1, A a2 ) { return A{ a1.value() - a2.value() } ; }
};
// there is no requirement that the definition of a friend must appear within the body of the class
A operator+ ( A a1, A a2 ) { return A{ a1.value() + a2.value() } ; }
int main()
{
const A a1(22), a2(35) ;
constauto a3 = a1 + a2 ;
constauto a4 = a1 - a2 ; // operator- is found via adl
std::cout << a3.value() << ' ' << a4.value() << '\n' ; // 57 -13
}