Читаем Программирование полностью

                                // потока cout

int main()

{

  cout << f(i) << '\n';

}

Теперь осталось только две ошибки, вызванных отсутствием определения идентификаторов. При создании реальных программ большинство определений размещают в заголовочных файлах. Именно там определяются интерфейсы полезных функциональных возможностей, которые сами определяются “в другом месте”. В принципе объявление лишь устанавливает, как некая сущность может быть использована; оно определяет интерфейс функции, переменной или класса. Следует помнить об одном очевидном, но невидимом преимуществе такого использования объявлений: мы можем не беспокоиться о деталях определения потока cout и его операторов <<; мы просто включаем их объявления в программу с помощью директивы #include. Мы можем даже не заглядывать в их объявления; из учебников, справочников, примеров программ и других источников нам известно, как используется поток cout. Компилятор считывает объявления из заголовочных файлов, необходимых для понимания кода.

Однако нам по-прежнему необходимо объявить переменные f и i. И сделать это можно следующим образом:

#include "std_lib_facilities.h" // здесь содержится объявление

                                // потока cout

int f(int); // объявление переменной f

int main()

{

 int i = 7; // объявление переменной i

 cout << f(i) << '\n';

}

Этот код компилируется без ошибок, поскольку каждое имя было определено, но он не проходит редактирование связей (см. раздел 2.4), поскольку в нем не определена функция f(); иначе говоря, мы нигде не указали, что именно делает функция f().

Объявление, которое полностью описывает объявленную сущность, называют определением (definition). Рассмотрим пример.

int a = 7;

vector v;

double sqrt(double d) {/* ... */}

Каждое определение — это объявление, но только некоторые объявления одновременно являются определениями. Ниже приведены некоторые примеры объявлений, которые не являются определениями; каждому из них должно соответствовать определение, размещенное где-то в другом месте кода.

double sqrt(double); // здесь функция не имеет тела

extern int a;        // "extern плюс отсутствие инициализатора"

                     // означает, что это — не определение

Сравнивая определения и объявления, мы придерживаемся общепринятого соглашения, которое устанавливает, что объявлением считается только объявление, не являющееся определением, даже если вас немного запутывает такая терминология.

Определение устанавливает, на что именно ссылается имя. В частности, определение переменной выделяет память для этой переменной. Следовательно, ни одну сущность невозможно определить дважды. Рассмотрим пример.

double sqrt(double d) {/* ... */} // определение

double sqrt(double d) {/* ... */} // ошибка: повторное определение

int a; // определение

int a; // ошибка: повторное определение

И наоборот, объявление, которое не является одновременно определением, просто сообщает, как можно использовать имя; оно представляет собой интерфейс, не выделяет памяти и не описывает тело функции. Следовательно, одно и то же имя можно объявлять несколько раз при условии, что объявления являются согласованными.

int x = 7;                        // определение

extern int x;                     // объявление

extern int x;                     // другое объявление

double sqrt(double);              // объявление

double sqrt(double d) {/* ... */} // определение

double sqrt(double);              // другое объявление функции sqrt

double sqrt(double);              // еще одно объявление функции sqrt

int sqrt(double);                 // ошибка: несогласованное определение

  Почему последнее объявление является ошибкой? Потому что в одной и той же программе не может быть двух функций с именем sqrt, принимающих аргумент типа double и возвращающих значения разных типов (int и double).

Перейти на страницу:
Нет соединения с сервером, попробуйте зайти чуть позже