Как и в языке Objective-C, интерфейсный файл(описывающий, например, абстракцию игральной карты) может содержать описания более чем одного класса, хотя обычно это происходит, только если классы тесно связаны. Поскольку языкиC иC++ не поддерживают ключевого словаimport (в отличии отObjective-C), для достижения того же эффекта используется условное подключение файла. Когда файлcard.h считывается впервые, символCARDH (предполагается, что он не встречается в других местах) является неопределенным, и тем самым срабатывает условный операторifndef (если не определено), так как значениеCARDH действительно не определено. Значит, файлcard.h будет считан. При всех последующих попытках считать этот файл символ будет известен, и загрузка файла будет пропущена.
# ifndef CARDH // файл должен читаться лишь один раз
#define CARDH
. . .
#endif
Описание класса начинается с ключевого слова class (листинг3.6). ВC++ описание класса во многом напоминает структуру в языкеC, за исключением того, что вместе с полями данных стоят заголовки процедур. Ключевое словоprivate: предшествует фрагментам кода, доступ к котором разрешен только из самого класса. Ключевое словоpublic: обозначает область интерфейса— то есть то, что видно извне класса. Как и в языкеObjective-C, описание переменных экземпляра в областиprivate дается в интерфейсном файле только ради компилятора(чтобы он мог определить размер памяти, требуемой для объекта), а для пользователя данного класса эти поля остаются недоступными(что является нарушением первого принципа Парнаса).
Поскольку пользователи часто интересуются открытой областью интерфейса public, эта часть должна идти первой. Как и выше, следует использовать комментарии, табуляцию, группирование и упорядочивание по алфавиту, чтобы сделать описание более читаемым.
Функция card(suit, int) в описании класса является уникальной во многих отношениях— не только потому, что ее имя совпадает с именем класса, но и потому, что у нее нет возвращаемого значения. Эта функция называется конструктором, она используется при инициализации создаваемых экземпляров класса. Мы обсудим конструкторы более подробно в главе4.
Ключевое слово void, как и в языкеObjective-C, показывает отсутствие типа. Когда оно используется как тип возвращаемого значения, это означает, что метод применяется как процедура ради побочного эффекта, а не для вычисления результата.
Методы draw иhalfdraw иллюстрируют описание типов параметров как составной части объявления функции. Этот стиль декларирования называется прототипом функции. Теперь он является частьюANSI стандарта языковC иC++. Заметьте, что прототип аналогичен списку аргументов, хотя аргументы представлены как типы данных и их имена являются необязательными.
Аргумент с типом данных window, обрабатываемый функциейdraw, передается через ссылку. На это указывает& в списке аргументов. Большие структуры, вроде описания окон(тип данныхwindow в нашем примере), часто передаются через ссылку.
Листинг 3.6. Описание класса сard на языкеC++
enum suits {diamond, club, heart, spade};
enum colors {red, black};
//абстракция игральной карты
//используется в пасьянсе
//язык программирования: C++
//автор: Тимоти Бадд, 1995
class card{ public:
//конструктор
card (suits, int); | ||
// доступ к атрибутам карты | (); | |
colors | color | |
bool | faceUp | (); |
int | rank | (); |
suits | suit | (); |
// выполняемые действия
void | void | draw | (window &); |
halfdraw (window &, int x, int y); | |||
void | flip | (); | |
private: | faceup; | ||
bool | r; | ||
suits | int | // ранг | |
s; | // масть | ||
}; |
Поскольку методы рассматриваются просто как поля специального вида, принадлежащие объекту и неразличимые от полей данных, метод и поле данных не могут иметь общего имени. Тем самым переменнаяs хранит значение, представляющее собой масть карты, в то время как методsuit возвращает это значение. Аналогично идентификаторыr иrank нужны для хранения и для возврата ранга карты.
Файл реализации для данного класса должен обеспечить работу методов, описанных в интерфейсном файле. Начало файла реализации для нашей абстракции игральной карты показано ниже.
//
//файл реализации
//для абстракции игральной карты
# include «card.h» card::card (suits sv, int rv)
{