2012-05-15 2 views
1

С момента моего перехода с C на C++ у меня есть вопрос о выходе форматирования STL. Как ostreams сообщают один базовый тип от другого?Как cout отличает базовые типы?

В C с его printf и строками форматирования это было довольно просто, но в C++ ostreams каким-то образом различают базовые типы автоматически. Меня это озадачивает.

Например, в следующем коде,

int i; 
float f; 

std::cout << i << std::endl; 
std::cout << f << std::endl; 

как соиЬ «знает», что я является ИНТ и е с плавающей точкой?

+0

Потоки никогда не имели ничего общего с STL. Вы думаете о стандартной библиотеке C++. –

ответ

7

Компилятор преобразует операторы в вызовы функций. Так что

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); 
    ... 
}; 

То же основная идея имеет, однако.

+2

Не все 'operator <<' являются свободными функциями, перегрузки 'int' и' float' являются [функциями-членами] (http://en.cppreference.com/w/cpp/io/basic_ostream/operator_ltlt). 'std :: cout.operator << (int i);' –

+0

@JesseGood: Хорошая точка. Поэтому мой пример не совсем корректен. Это по-прежнему в основном правильное, и я чувствую, что его изменение идеально будет заслонять основную идею. Не говоря уже о том, чтобы попытаться описать, как на самом деле кодируется 'std :: endl' ... – Managu

+0

... и да, я знаю, что нет' класса ostream' ... – Managu

2

разрешение перегрузки на второй аргумент operator<<

3

Есть операторы < < перегрузки для каждого типа (int, float и т. Д.). Затем компилятор выбирает правильный во время компиляции. В общем случае оператор < < имеет форму std::ostream& operator<<(std::ostream& stream, int number), где функция является глобальной функцией, определенной в пространстве имен std. Вы можете перезаписать определение этой функции, объявив ее в своем собственном пространстве имен (это делается с помощью зависимого от аргумента поиска).

Тот факт, что функция возвращает ссылку на поток, означает, что вы можете связать их вместе. Просто помните, когда вы видите оператора < <, это действительно вызов функции.

Если вы хотите, чтобы посмотреть, и вы используете VS, откройте

C: \ Program Files (x86) \ Microsoft Visual Studio 9.0 \ VC \ Include \ ostream.

Здесь вы найдете все определения, если вам интересно.

1

Перегрузка функций - это форма полиморфизма времени компиляции. Простой пример:

void times_two(int& x) { x *= 2; } 
void times_two(double& x) { x *= 2; } 

int i = 2; 
double d = 2.5; 

times_two(i); // i now 4 
times_two(d); // d now 5.0 

В случае std::ostream с такими как std::cout, перегрузки operator<<() функций в аналогичным образом. Из стандартной библиотеки, поставляемой с GCC 3.4.4:

__ostream_type& 
operator<<(int __n); 

__ostream_type& 
operator<<(double __f); 
Смежные вопросы