Объектно-ориентированное программирование

Как и в языке 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)

{