Overloading << and >> in inherited classes - c++

I have class Person (first name, last name, address, age) and overloaded operators << and >> to use it with filestreams:
ostream& operator<< (ostream& outStream, Person& person)
{
...
}
istream& operator>> (istream& inStream, Person& person)
{
...
}
It works fine - I can read from and write to file easily, but I have added two classes inherited from Person: Student and Worker.
I wrote overloaded operators for them, very similar to those above:
ostream& operator<< (ostream& outStream, Worker& worker)
{
...
}
istream& operator>> (istream& inStream, Worker& worker)
{
...
}
ostream& operator<< (ostream& outStream, Student& student)
{
...
}
istream& operator>> (istream& inStream, Student& student)
{
...
}
Only difference are two more fields in each class. The problem is, that when I use overloaded operators with either Student or Worker it seems my compiler uses operators for person. Probably it makes hidden conversion from Student or Worker to Person, but as a result there are no those additional fields written to the file.
offstream << People works just the same as offstream << Students or offstrem Workers.
Maybe placing overloaded operators declarations for inherited classes first, and for Person later in the code would solve the issue, but i don't find it an elegant solution.
If you have some ideas how to manage with the problem above, I would appreciate.

Two things. First, make your operators take references to const, like this:
ostream& operator<< (ostream& outStream, const Person& person)
To solve your problem, a common pattern is to provide your types with a protected virtual toString method, and have the operator just call that. You can then just overload this method in the sub-classes, and even reuse the super-class implementation if you just want to append some values to the string.
Example:
class Person {
// other stuff
protected:
virtual std::string toString();
friend ostream& operator<< (ostream& outStream, const Person& person)
};
ostream& operator<< (ostream& outStream, Person& person)
{
ostream << person.toString();
return outStream;
}
Edit
Actually, I like larsmans suggestion even better:
class Person {
// other stuff
protected:
virtual void print(ostream & stream) const;
friend ostream& operator<< (ostream& outStream, const Person& person)
};
ostream& operator<< (ostream& outStream, Person& person)
{
person.print(outStream);
return outStream;
}
This will be easier to implement than the toString idea, because you need no temporary stringstream or anything like that to build the string.

Most probably the code which calls the << operator accesses the object through a pointer or reference to Person, thus calling the operator for the Person type. The usual way of handling this is to provide a virtual method on the parent (i.e. Person) class which does the writing (getting the stream as an argument), and have the operator<< call this method to do the work. You need to provide the operator<< only for the parent class, the virtual dispatch mechanism will take care of choosing the right method for the object provided.
class Person {
// ...
protected:
virtual ostream& stream_write(ostream&) const; //override this in child classes
virtual istream& stream_read(istream&); //this too
public:
friend ostream& operator<< (ostream& stream, const Person& obj)
{ return obj.stream_write(stream); }
friend istream& operator>> (istream& stream, Person& obj)
{ return obj.stream_read(stream); }
};

Your operators could call a virtual method. Something like this :
struct A
{
virtual ~A(){}
virtual std::ostream& Print( std::ostream &os ) const
{
// print what you want
return os;
}
};
struct B : A
{
virtual ~B(){}
virtual std::ostream& Print( std::ostream &os ) const
{
// print what you want
return os;
}
};
Then create the operator<< only for the base class :
std::ostream& operator<<( std::ostream &os, const A &a)
{
return a.Print(os);
}

I usually call a virtual function streamIn and streamOut in the overloaded streaming operators, in that way I can actually create a template streaming function that works for all classes with streamIn and streamOut functions.

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

Output operator (<<) for abstract class and derived class

I have 2 classes, a abstract base class & derived class.
But for some reason i cannot properly overload the output operators for both.
Here is the base class:
class team
{
char* team_name;
int games_played;
public:
team(const char* tname);
virtual ~team();
virtual void update_lpoints(const int win_loss)=0;
friend std:: ostream& operator<< (std :: ostream& out, team& T);
};
std:: ostream& operator<< (std :: ostream& out, team& T);
And here is the output operator:
std:: ostream& operator<< (std :: ostream& out, team& T)
{
return (out<<T.team_name<<" "<<T.games_played);
}
The derived class:
class BasketTeam : public team
{
int league_points;
int points_for;
int points_against;
public:
BasketTeam(const char* tname);
~BasketTeam();
friend std:: ostream& operator<< (std :: ostream& out, BasketTeam& T);
};
std:: ostream& operator<< (std :: ostream& out, BasketTeam& T);
Here is the output operator for the derived class:
std:: ostream& operator<< (std :: ostream& out, BasketTeam& T)
{
out<<T.get_name()<<" "<<T.get_played_games()<<" "<<T.league_points<<" "<<T.points_for<<" "<<T.points_against<<endl;
return out;
}
When I create the object and try to print it i can only get the base class to appear not the derived class.
team* tt = new BasketTeam ("ran");
cout<<*tt;
Thanks in advance.
The overloaded operator << is selected on compile time, based on the static types of the arguments. Since tt's static type is team, that's the operator << that it used.
If you want the dynamic type of the object to determine the output, you have to use some other technique. For instance, you can have team contain a virtual print function, and override it in BasketTeam. Then, have one operator << take a team& t, and call t.print() or so. This will invoke the print method according to the dynamic type of t, which is what you are looking for.

simple c++ operator overloading help

How do I overload the << operator? From the error I am getting, it seems that std::cout doesn't know how to use <<.
This is in a class:
// uint64_t UPPER, LOWER;
std::ostream & operator<<(std::ostream & stream){
if (UPPER)
stream << UPPER;
stream << LOWER;
return stream;
}
I am getting error: no match for 'operator<<' in 'std::cout << test' which doesn't seem to make sense.
edit:
Neither this:
std::ostream & operator<<(std::ostream & stream, uint128_t const & val){
if (val.upper())
stream << val.upper();
stream << val.lower();
return stream;
}
nor this:
std::ostream & operator<<(std::ostream & stream, uint128_t val){
if (val.upper())
stream << val.upper();
stream << val.lower();
return stream;
}
is changing the error.
The << operator takes two arguments, a left hand side, and a right hand side. Therefore you have to define the function with two parameters:
std::ostream operator<<(std::ostream &os, const MyClass &obj);
And you have to define it outside of your class definition, as far as I can remember. Inside of the class definition you can only have operators that take that class as the left hand side.
You typically want the operator<<() overload to be a 'free function' (outside of your class) so it can bind to the stream naturally:
// this is outside your class definition
std::ostream& operator<<(std::ostream& os, const myclass& rhs)
{
// whatever...
return os;
}
Then inside your class you declare it a friend if necessary so it can get to the class internals:
friend std::ostream& operator<<(std::ostream& os, const myclass& rhs);
An alternative to having this be a friend (which some people consider to be breaking encapsulation) is to have a public function in your class that will output itself to a stream and call that in your operator<<() overload:
// inside class myclass - a normal public member function
std::ostream& dump( std::ostream& os)
{
os << some_class_member;
// ...
return os;
}
// now, the `operator<<()` overload doesn't need to be a friend
// this is still outside your class definition
std::ostream& operator<<(std::ostream& os, const myclass& rhs)
{
return rhs.dump(os);
}
operator<< outside a class requires two arguments:
std::ostream& operator<<(std::ostream& stream, type_you_want_output const& thing)

overloading the << operator in c++

hey, i got something that i cannot understand ,there are two types of solutions for overloading this operator 1 is including the friend at the start of the method and the other 1 goes without the friend.
i would very much like if some1 explain whats the difference between them advantages / disadvantages.
for example overloading the operator << in class rational:
class Rational:
{
private: int m_t,m_b;
...
friend ostream& operator<<(ostream& out,const Rational& r) // option 1
{ return out << r.m_t << "/" <<r.m_b;} // continue of option 1
ostream& operator<<(ostream& out,const Rational& r){return r.print();} // option 2
virtual ostream& print(ostream& out) const // continue of option 2
{ //
return out<<m_t << "/" << m_b;
} //
};
i was told that the second option isnt correct , if some1 can correct me about it i would much appriciate it.
thanks in advance.
The short answer: Option #2 actually isn't an option, but a syntax error, because it tries to define a binary operator as a member passing two operands.
The somewhat longer answer: If you make the second operand a free function (not a member of the class), this will work. Which one is preferable depends on the circumstances and your preferences. For starters: The disadvantage of the first is that it allows operator<< to access everything in Rational (including private helper functions), while the disadvantage of the second is that you introduce a function to the class' public API that nobody needs.
operator<< (for ostream) needs to be a free function (since the left-hand argument is a stream, not your class).
The friend keyword makes it a free function (a free function that has access to the private members).
However, if this functionality can be implemented in terms of the public interface, it is better to do so and just use a non-friend free function.
class Rational:
{
private: int m_t,m_b;
public:
...
virtual ostream& print(ostream& out) const
{
return out<<m_t << "/" << m_b;
}
};
ostream& operator<<(ostream& out,const Rational& r)
{
return r.print(out);
}
Consider a function that should output the num and den of Rational:
ostream& operator<<(ostream& out, const Rational& r)
{
return out;
}
Unfortunately, this is just a global function. Like any other global function, it cannot access the private members of Rational. To make it work with Rational objects, you need to make it friend of Rational:
class Rational
{
private: int m_t,m_b;
// ...
friend ostream& operator<<(ostream& out, const Rational& r);
};
ostream& operator<<(ostream& out, const Rational& r)
{
out << r.m_t << "/" <<r.m_b;
return out;
}
The friend ostream& operator<<(ostream& out, const Rational& r); inside Rational class indicates that ostream& operator<<(ostream& out, const Rational& r) function can directly use Rational's private members.
Now when you write:
Rational r(1, 2); // Say, it sets num and den
cout << r;
the following function call is made:
operator<<(cout, r);
Can you write operator<< as a member function of Rational? That's simply not possible because of the above conversion where cout has to be first parameter. If you make operator<< as a member of Rational:
class Rational
{
private: int m_t,m_b;
// ...
public:
ostream& operator<<(ostream& out) const
{
out << r.m_t << "/" <<r.m_b;
return out;
}
};
you need to call it this way:
Rational r(1, 2);
r.operator<<(cout);
which is ugly.

How to define class-specific << operator in C++

Given a class such as:
class Person
{
private:
char *name;
public:
Person()
{
name = new char[20];
}
~Person()
{
delete [] name;
}
}
I want to print to print the name from an instance of this, using a statement like the following:
cout << myPerson << endl;
What do I need to do to define the << output operator for this class?
add this in the class:
friend std::ostream& operator<< (std::ostream& out, const Person& P);
and then define the operator<< something like this:
std::ostream& operator<< (std::ostream& out, const Person& P) {
out << P.name;
return out;
}
Define a member function print() that takes an ostream as an argument. Then let the overloaded operator<< call this member function. This way you can avoid using friend. Example:
void YourClass::print(ostream& out) const
{
//implement printing ...
}
ostream& operator<<(ostream& out, const YourClass& m)
{
m.print(out);
return out;
}