Компилятор преобразует операторы в вызовы функций. Так что
std::cout << i
становится
operator<<(std::cout, i)
Где-то глубоко погребены в недрах стандартных заголовков библиотеки есть функция декларации (функционально эквивалентны):
std::ostream& operator<<(std::ostream& o, int i);
std::ostream& operator<<(std::ostream& o, double d);
То есть, operator<<
является перегружен. Когда вызов функции выполняется, компилятор выбирает функцию перегрузки, которая наилучшим образом соответствует переданным аргументам.
В случае std::cout << i
выбрана перегрузка int
. В случае std::cout<<d
выбрана перегрузка double
.
Вы можете увидеть функцию перегрузки в действии достаточно просто с надуманным примером:
#include <stdio.h>
void print(int i) {printf("%d\n", i);}
void print(double d) {printf("%f\n", d);}
int main()
{
int j=5;
double f=7.7;
print(j);
print(f);
}
Производство вывода:
5
7.700000
Попробуйте сам: http://ideone.com/grlZl.
Редактировать: Как отмечает Джесси Добрый, функции, о которых идет речь, являются функциями-членами. Так на самом деле мы имеем:
std::cout << i
становится
std::cout.operator<<(i)
И в заголовках есть декларации (эквивалент):
class ostream {
ostream& operator<<(int i);
ostream& operator<<(double d);
...
};
То же основная идея имеет, однако.
Потоки никогда не имели ничего общего с STL. Вы думаете о стандартной библиотеке C++. –