2

i just finished c++ essential training from linkedin learning and now i have simple question. Why does cout makes an output, we are just calling the object, but why does merely calling of an object does something. My guess is that the '<<' overloaded operator is the one that does something, but then here comes the '<< std::endl;' , with endl we are again just calling the object but it creates a new line. Can anyone explain why is it like this?

rici
  • 234,347
  • 28
  • 237
  • 341
Renz Carillo
  • 349
  • 2
  • 11
  • What do you mean by "calling an object"? – bolov Apr 14 '21 at 02:28
  • 1
    Yes it does perform operator operator overloading but it's not as intuitive. What it does is create an ostream object which takes an input object as an argument and returns the ostream. So std::endl is an object similar to a string or an object that overloads the string stream operator – Irelia Apr 14 '21 at 02:28
  • @bolov cout is an object of class ostream. What i mean is by doing 'std::cout', we are calling the object cout of class ostream – Renz Carillo Apr 14 '21 at 02:32
  • https://stackoverflow.com/questions/10676336/c-stl-cout-source-code – Mario Abbruscato Apr 14 '21 at 02:35
  • 1
    Ok, there is some terminology that we need to address in order for us to speak the same language. Writing `std::cout` is not "calling" the object. Calling involves a function/method. Calling an object `x` would look like `x()` and that would only be valid if the type of `x` has an `operator()` defined.. – bolov Apr 14 '21 at 02:43
  • https://stackoverflow.com/questions/33553091/where-is-endl-manipulator-defined – user3386109 Apr 14 '21 at 03:13
  • good of you for asking this, as you are trying to understand instead of just accepting the newly learned. – Stack Danny Apr 14 '21 at 03:35

1 Answers1

6

std::cout is an ostream object that is available through the standard library. When you invoke

std::cout << 42;

It looks for an overload of ostream& operator<<(ostream&, int) or in this case, a member function of the object (ostream& operator<<(int)), and passes cout to this operator (or as this), and the integer. The body of the operator writes the integer value into the stream and returns the stream object, allowing chaining:

std::cout << 42 << std::endl;

is really inserting 42 into the ostream, returning cout, and then "inserting" endl into the stream, which finds another overloaded operator, which writes a newline and then flushes the stream. std::ostream (which std::cout is one of) has a handful of built-in operator<< overloads as members, but for ordinary user-defined types, you usually write non-member operator<< overloads, or member friend overloads.

It's not magic, but it is a little subtle because infix operators are, in this case, translated into "normal" function calls. Thus for some object x of type X with an overloaded operator<< for it:

class X { /*impl stuff*/ };
std::ostream& operator<<(std::ostream&, X const&);

then

std::cout << x << std::endl;

can be thought of as a pretty way of doing this:

(std::operator<<(std::cout, x)).operator<<(std::endl);

Where the inner operator<< is called first, overloaded for x, and its return value (which is cout) has its member function operator<< called with std::endl as the argument. For the curious, std::endl is actually a function, we are passing a function pointer to this overload of operator<<, which is a member of std::cout:

// member overload of operator<< which is used with std::endl
basic_ostream& operator<<(
    std::basic_ostream<CharT,Traits>& (*func(
        std::basic_ostream<CharT,Traits>&)
);

This is the normal way that stream manipulators work. It seems a little convoluted, but it allows a nice looking sequence of << tokens without having to write out parenthesis or "dots" in the chain of expressions. It actually will insert a function into the stream, the operator<< receives the function pointer, calls that function passing the stream object to it (that is, invokes std::endl(this)), and then endl runs as a normal function that inserts a newline into the stream and calls flush() on it, and then returns the stream, which can be used by the next chained call to operator<<.) This is a level of detail that few people actually need to know (or care about) unless you're writing manipulators, but it's interesting IMHO.

Chris Uzdavinis
  • 6,022
  • 9
  • 16
  • 1
    The operator<< for ostream and int is a member function, not a free function. Other than this small nit pick, great explanation – bolov Apr 14 '21 at 02:47