Why does merely calling of an object does something?

Viewed 84

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?

1 Answers

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.

Related