Говорят, что переменная описана (определена), если она объявлена и под неё выделена память. Рассмотрим следующий пример, пусть в проекте есть два файла:
/* a.cpp */
extern int n; // "Где-то дальше определено"
void f(int); // Предварительное объявление
void main() {
n = 5; f(n);
}
/* b.cpp */
#include <iostream>
int i; // Описание переменной
// Определение функции
void f(int i) {
std::cout << i;
}
В C++ имеет место независимая компиляция: все файлы проекта компилируются независимо один от другого. Компиляция состоит из этапа собственно компиляции и этапа линковки.
Содержат заголовки всех функций и объявления переменных, обычно имеют
расширение *.h
(header). Теперь можно вынести объявления функций из всех
файлов в один (заголовочный):
/* myheader.h */
extern int n;
void f(int);
/* myheader.cpp */
#include <iostream>
int n;
void f(int i) {
std::cout << i;
}
/* a.cpp */
#include "myheader.h"
void main() {
n = 5; f(n);
}
/* b.cpp */
#include "myheader.h"
void makeZero() {
n = 0;
}
Имена пользовательских заголовочных файлов в директиве include
заключаются в двойные кавычки, а имена стандартных заголовочных файлов —
в угловые скобки. Стандартные заголовочные файлы расположены в /INCLUDE
.
Поиск пользовательских файлов производится в текущем каталоге.
Замечание: inline-функции не сохраняются в исходном коде, так как больше не используются (а сразу встраиваются на место вызова). Чтобы воспользоваться такими функциями в другой единице компиляции, их нужно поместить в заголовочный файл.
Что может содержать заголовочный файл:
Пример | |
---|---|
Определения типов | struct point { int x, y; }; |
Шаблоны типов | template<class T> class V { /* ... */ } |
Описания функций | extern int strlen(const char*); |
Определения встраиваемых функций | inline char get() { return *p++; } |
Описания данных | extern int a; |
Определения констант | const float pi = 3.141593; |
Перечисления | enum bool { false, true }; |
Описания имен | class Matrix; |
Команды включения файлов | #include <signal.h> |
Макроопределения | #define Case break;case |
Комментарии | /* проверка на конец файла */ |
В заголовочном файле никогда не должно быть:
Пример | |
---|---|
Определений обычных функций | char get() { return *p++; } |
Определений данных | int a; |
Определений составных констант | const tb[i] = { /* ... */ }; |
При простом определении глобальных сущностей они объединяются в глобальном пространстве имен. Для создания локального пространства имен используется ключевое слово namespace
.
namespace MyNamespace{
... // содержимое пространства имён: типы, функции, что-угодно…
}
Прототипы функций и глобальные переменные в заголовочных файлах, особенно в крупных проектах, необходимо заключать в пространства имен.
/* header.h */
namespace MyNamespace{
extern int n;
void f();
}
*.cpp
-файла в объектный код (файлы *.obj
или *.o
).*.exe
или ELF
).#include "*.cpp"
(грубая ошибка).main()
во всех файлах проектах.main()
.inline
-функции «погибают» при компиляции.