Why We Need to Return Reference to Istream/Ostream While Overloading >> and << Operators

Why we need to return reference to istream/ostream while overloading and operators?

The reason is a combination of several facts.

  1. You want to be able to chain input and output operations as in

    in  >> x >> y;

    out << z << std::precision(10) << t << std::endl;

    so you must return something that allows operator<< again.

  2. Since you want your operator to work on any istream, i.e. any object derived from std::istream, you cannot define

    operator<<(istream_type, object);    // take istream by value

    since this would only work for the specific istream type istream_type, but not for a generic istream. For that one must use polymorphism, i.e. either take a reference or a pointer (which will be a reference or pointer to a class derived from std::istream).

  3. Since you only have a reference to the istream, you cannot return the istream object itself (which may be of a type not even defined at the point of the definition of operator<<) but only the reference you've got.

    One could get around this restriction by defining operator<< a template and take and return the istream_type by value, but that requires the istream type to have a copy constructor, which it may well not have for good reasons.

  4. In order to envoke polymorphism one could, in principle, use pointers (to streams) rather than references. However, operator<<(stream*,const char*) is
    not allowed in C++ (at least one operand must be of class or enumeration type).

    Thus, with stream pointers one must use function-call syntax and you're back with C-style fprintf(stream*, args...).

    Moreover, pointers can be null or dangling, which in fact is their default state (when declared without initializer), while a reference can be assumed to be valid (it cannot be declared without initializer).

Why does overloading ostream's operator need a reference &?

why does this function need "&" at the end of ostream and Object?

Because you are passing them by reference.

Why are you passing them by reference. To prevent a copy.

ostream& operator<<(ostream& out, Objects const& obj)
// ^^^^^ note the const
// we don't need to modify
// the obj while printing.

The obj can be copied (potentially). But what if it is expensive to copy. So best to pass it by reference to prevent an unnecessary copy.

The out is of type std::ostream. This can not be copied (the copy constructor is disabled). So you need to pass by reference.

I normally declare the stream operator direcctly in the class declaration:

class X
{
std::string name;
int age;

void swap(X& other) noexcept
{
std::swap(name, other.name);
std::swap(age, other.age);
}
friend std::ostream& operator<<(std::ostream& str, X const& data)
{
return str << data.name << "\n" << age << "\n";
}
friend std::istream& operator>>(std::istream& str, X& data)
{
X alt;
// Read into a temporary incase the read fails.
// This makes sure the original is unchanged on a fail
if (std::getline(str, alt.name) && str >> alt.age)
{
// The read worked.
// Get rid of the trailing new line.
// Then swap the alt into the real object.
std::string ignore;
std::getline(str, ignore);
data.swap(alt);
}
return str;
}
};

Why does a insertion/extraction operator's overloaded function need ostream/istream argument?

Because in both cin >> test and cout << test, two arguments exist.

cin is of type istream.

cout is of type ostream.

These types could be other things than cout and cin. For example, they could be cerr, clog, or stringstream.

That's why you need two arguments, since the one is the variable for the stream and the other is the object to be streamed.

return type in stream operator overloading

In the example, if data is taken from input stream cin and the values are assigned inside the function, why should istream be returned back?

This is done to allow "chaining".

The operator takes its two parameters from both sides of >>. The stream comes from the left, and the variable comes from the right. When you do this

cin >> x >> y;

the first expression cin >> x is on the left of the second expression, which means that the result of cin >> x becomes ... >> y's input stream. That is why the operator needs to return the same input stream that has been passed into it.

why overloading of operator must return by reference?

In the first example, you return a copy of the stream object which is not allowed because the copy-constructors (and copy-assignment as well) of all the stream classes in C++ has been disabled by having them made private.

Since you cannot make a copy of a stream object, you're required to return it by reference, which you're doing in the second example which is why it is working fine.

You may choose to return nothing at all (i.e you can make the return type void), but if you do so, then you would not be able to chain as stream << a << b. You've to write them separately as stream <<a and then stream << b.

If you want to know why copying of stream objects is disabled, see my answer here:

  • Why copying stringstream is not allowed?

istream ostream Operator Overloading with * Pointer

It depends on what is in the class Classname. If for example you have:

class Classname {
//...
private:
int a;
};

.. then you might do:

std::ostream& operator <<( std::ostream& outs, const Classname * e)
{
outs << e->a;
return outs;
}
std::istream& operator >>( std::istream& ins, Classname* & e){
ins >> e->a;
return ins;
}

The idea being that the << and >> operators ideally should mirror each other - so for example you can make use of them for serializing and deserializing your instances.

Operator overloading return type

You can return void from stream extracting operator >>, just like you can return void from a stream inserting operator <<. And just like with the inserting one, it will prevent you from doing chaining:

cPoint p, q;
cin >> p >> q; // This would fail with return type void

... and the very common test-correctness idiom:

cPoint p;
if (cin >> p) {
}


Related Topics



Leave a reply



Submit