Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I've been learning C++.

From this page, I understood that overloading "<<" operator of ostream can be done in this way.

ostream& operator<<(ostream& out, Objects& obj) {
    //
    return out;
} 
//Implementation

and

friend ostream& operator<<(ostream& out, Object& obj);
//In the corresponding header file

My question is... why does this function need "&" at the end of ostream and Object?

At least I know that "&" is used to...

  1. Take the address of a value
  2. Declare a reference to a type

However, I think neither of them applies to the overloading described above. I've spent a lot of time in googling and reading a text book, but I can't find the answer.

Any advice will be appreciated.

like image 649
Hiroki Avatar asked May 16 '15 05:05

Hiroki


1 Answers

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;
    }
};
like image 51
Martin York Avatar answered Sep 30 '22 20:09

Martin York