7

I'd like to know how do stream classes work in C++. When you say:

cout<<"Hello\n";

What does exactly do "<<". I know that cout is an object form iostream that represents the standard output stream oriented to narrow characters (char).

In C "<<" is the bitwise shift operator so it moves bits to the left but in C++ it's and insertion operator. Well, that's all I know, I don't really understand how does this work under the hood.

What I'm asking for is detailed explanation about stream classes in C++, how they are defined and implemented.

Thank you very much for your time and sorry for my English.

Mihai
  • 509
  • 5
  • 14
  • 1
    See http://www.cplusplus.com/doc/tutorial/basic_io/ and http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/ – Robert Harvey Apr 23 '14 at 19:12
  • 3
    C++ supports [operator overloading](http://stackoverflow.com/questions/4421706/operator-overloading). Don't confuse ([`ostream.<<`](http://www.cplusplus.com/reference/ostream/ostream/operator%3C%3C/)) it with the same-looking operator in a *different context*, such as for integers. That is, operators simply provider a cleaner (?) way of writing "normal" method names, like `cout.insertFormattedOutout("Hello\n")`. – user2864740 Apr 23 '14 at 19:12
  • The << is an operator, similar to "+". Think of it as saying push the string "Hello\n" into the object cout. One could define another operator like "+" to do the same thing. – imran Apr 23 '14 at 19:16
  • detailed explanation? hmmm... http://www.cprogramming.com/tutorial/c++-iostreams.html – 101010 Apr 23 '14 at 19:20

3 Answers3

13

Let's create a class that looks like cout (but without as many bells and whistles).

#include <string>

class os_t {
    public:
        os_t & operator<<(std::string const & s) {
            printf("%s", s.c_str());
            return *this;
        }
};

int main() {
    os_t os;

    os << "hello\n";
    os << "chaining " << "works too." << "\n";
}

Notes:

  • operator<< is an operator overload just like operator+ or all of the other operators.
  • Chaining works because we return ourselves: return *this;.

What if you can't change the os_t class because someone else wrote it?

We don't have to use member functions to define this functionality. We can also use free functions. Let's show that as well:

#include <string>

class os_t {
    public:
        os_t & operator<<(std::string const & s) {
            printf("%s", s.c_str());
            return *this;
        }
};

os_t & operator<<(os_t & os, int x) {
    printf("%d", x);
    return os;

    // We could also have used the class's functionality to do this:
    // os << std::to_string(x);
    // return os;
}

int main() {
    os_t os;

    os << "now we can also print integers: " << 3 << "\n";
}

Where else is operator overloading useful?

A great example of how this kind of logic is useful can be found in the GMP library. This library is designed to allow arbitrarily large integers. We do this, by using a custom class. Here's an example of it's use. Note that operator overloading let's us write code that looks almost identical to if we were using the traditional int type.

#include <iostream>
#include <gmpxx.h>

int main() {
    mpz_class x("7612058254738945");
    mpz_class y("9263591128439081");

    x = x + y * y;
    y = x << 2;

    std::cout << x + y << std::endl;
}
Bill Lynch
  • 80,138
  • 16
  • 128
  • 173
  • Sir, why did you create the free function that takes `int` as second parameter when `ostream` class overloads the `<< operator` for ints too? – asn Jan 11 '20 at 10:24
  • `os_t` is not a subclass of `ostream`. And the question here was basically how to implement a stream. – Bill Lynch Jan 11 '20 at 16:10
  • Actually, I am talking about the same(ostream). – asn Jan 11 '20 at 16:45
5

<< is a binary operator in C++, and thus can be overloaded.

You know of the C usage of this operator, where 1 << 3 is a binary operation returning 8. You could think of this as the method int operator<<(int, int) where passing in arguments 1 and 3 returns 8.

Technically, operator<< could do anything. It's just an arbitrary method call.

By convention in C++, the << operator is used for handling streams in addition to being the bit-shift operator. When you perform cout << "Hello!", you are calling a method with prototype ostream & operator<< (ostream & output, char const * stream_me). Note the return value ostream &. That return allows you to call the method multiple times, like std::cout << "Hello World" << "!"; which is calling operator<< twice... once on std::cout and "Hello World", and the second time on the result of that first invocation and "!".

In general, if you were to create a class named class Foo, and you wanted it to be printable, you could define your printing method as ostream & operator<< (ostream & output, Foo const & print_me). Here is a simple example.

#include <iostream>

struct Circle {
  float x, y;
  float radius;
};

std::ostream & operator<< (std::ostream & output, Circle const & print_me) {
  output << "A circle at (" << print_me.x << ", " << print_me.y << ") with radius " << print_me.radius << ".";
}

int main (void) {
  Circle my_circle;
  my_circle.x = 5;
  my_circle.y = 10;
  my_circle.radius = 20;

  std::cout << my_circle << '\n';

  return 0;
}
QuestionC
  • 10,006
  • 4
  • 26
  • 44
1

Operators can be considered functions with syntactic sugar that allow for clean syntax. This is simply a case of operator overloading.

Community
  • 1
  • 1
Veritas
  • 2,150
  • 3
  • 16
  • 40