
Несколько слов о заголовочных файлах
Заголовочный файл предоставляет место для всех extern-объявлений объектов, объявлений функций и определений встроенных функций. Это называется локализацией объявлений. Те исходные файлы, где объект или функция определяется или используется, должны включать заголовочный файл.
Пример с addToken() имеет следующий заголовочный файл:
//
----- token.h -----
typedef
unsigned char uchar;
const
uchar INLINE = 128;
//
...
const
uchar IT = ...;
const
uchar GT = ...;
extern
uchar lastTok;
extern
int addToken( uchar );
inline
bool is_relational( uchar tok )
{
return (tok >= LT && tok <= GT); }
//
----- lex.C -----
#include
"token.h"
//
...
//
----- token.C -----
#include "token.h"
//
...
extern
int i = 10;
double
fica_rate;
extern
void dummy () {}
Обычно включаемые файлы обычно содержат только описания и не содержат программ, требующих от компилятора значительного анализа.
Следующее эмпирическое правило относительно того, что следует, а что не следует помещать в заголовочные файлы, является не требованием языка, а просто предложением по разумному использованию аппарата #include. В заголовочном файле могут содержаться:
Определения типов |
struct point { int x, y; } |
Описания функций |
Extern int strlen(const char*); |
Определения inline-функций |
inline char get() { return *p++; } |
Описания данных |
Extern int a; |
Определения констант |
const float pi = 3.141593 |
Перечисления |
enum bool { false, true }; |
Директивы include |
#include |
Определения макросов |
#define Case break;case |
Комментарии |
/* проверка на конец файла */ |
но никогда
Определения обычных функций |
char get() { return *p++; } |
Определения данных |
int a; |
Определения сложных константных объектов |
const tbl[] = { /* ... */ } |
В предыдущих примерах .c и .h файлы вместе определяли часть программы. Файл .h является интерфейсом, который используют другие части программы; .c файл задает реализацию. Такой объект часто называют модулем. Доступными делаются только те имена, которые необходимо знать пользователю, остальные скрыты. Это качество часто называют скрытием данных, хотя данные - лишь часть того, что может быть скрыто. Модули такого вида обеспечивают большую гибкость. Например, реализация может состоять из одного или более .c файлов, и в виде .h файлов может быть предоставлено несколько интерфейсов. Информация, которую пользователю знать не обязательно, искусно скрыта в .c файлах. Если важно, что пользователь не должен точно знать, что содержится в .c файлах, не надо делать их доступными в исходом виде. Достаточно эквивалентных им выходных файлов компилятора (.o файлов).
Сколько заголовочных файлов использовать в программе, зависит от многих факторов. Многие из этих факторов сильнее связаны с тем, как ваша система работает с заголовочными файлами, нежели с C++. Например, если в вашем редакторе нет средств, позволяющих одновременно видеть несколько файлов, использование большого числа файлов становится менее привлекательным. Аналогично, если открывание и чтение 10 файлов по 50 строк в каждом требует заметно больше времени, чем чтение одного файла в 500 строк, вы можете дважды подумать, прежде чем использовать в небольшом проекте стиль множественных заголовочных файлов. Слово предостережения: набор из десяти заголовочных файлов плюс стандартные заголовочные файлы обычно легче поддаются управлению. С другой стороны, если вы разбили описания в большой программе на логически минимальные по размеру заголовочные файлы (помещая каждое описание структуры в свой отдельный файл и т.д.), у вас легко может получиться неразбериха из сотен файлов.
Наверное, вы считали, что интерфейс класса полностью определяется объявлением класса, но в действительности любой класс может иметь несколько разных интерфейсов в зависимости от клиента.
-
Класс и его друзья видят один интерфейс, включающий всех членов класса и всех защищенных и открытых членов его базовых классов.
-
Производные классы видят только защищенных и открытых членов класса и его базовых классов.
-
Все остальные клиенты видят только открытых членов класса и его базовых классов.
-
Если указатель на объект преобразуется к указателю на его базовый класс, интерфейс ограничивается только открытыми членами базового класса.
Открытые, закрытые и защищенные члены; открытое и закрытое наследование; полиморфизм и дружба
— все это лишь грубые синтаксические приближения более общей концепции дизайна: один объект может иметь много специализированных интерфейсов.
Таким образом, подобная организация программы обеспечивает модульность библиотеки, необходимую для сокрытия данных от пользователей, в то же время позволяя без ошибок скомпилировать и связать нужные файлы в одну программу.