Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
samples / Zaochniki / ООП.doc
Скачиваний:
26
Добавлен:
25.03.2015
Размер:
183.81 Кб
Скачать

№1 Объекты и классы

Объект — это абстрактная сущность, наделенная характеристиками объектов реального мира.

C++ объекты играют очень важную роль. Все, чем вы манипулируете в программе, может рассматривать­ся как объект. При выполнении программы объекты создаются и удаляются. Они взаимодействуют с другими объ­ектами и могут быть помещены в группы, коллекции, массивы, списки и т.д. В C++ многое (но не все), с чем работает программа, является объекта­ми. По этой причине C++ называют гибридным объектно-ориентированным языком.

Объекты в C++ — это программные конструкции, формируемые так называемыми классам. Определение пере­менной класса также называется созданием экземпляра класса (class instantiation). За создание своих классов полную ответственность несет сам программист. Но он может получить доступ и к классам, разработанным другими про­граммистами. Например, к классам, которые находятся в библиотеке контейнеров или библиотеке потоков компи­лятора Borland C++.

Главное отличие С от С++ — это классы. Уже само по себе существование классов в C++ является заме­чательной особенностью, делающей его объектно-ориентированным языком. Классы — это структуры, которые содержат не только объявления данных, но и функций. Эти функции называются функциями-членами (member functions) и определяют, что может делать класс.

Для того чтобы использовать класс, его нужно вначале объявить точно так же, как это делается со структура­ми. И так же как для структур, полное объявление класса может появиться в программе только один раз. Рассмот­рим пример объявления простого класса:

class Counter {

long count;

public:

void SetValue(long);

long GetValue() ;

};

Ключевое слово class вводит объявление класса. Далее следует имя клас­са. Тело класса должно заключаться в фигурные скобки, после которых стоит точка с запятой. Классы могут содер­жать не только объявления функций, но и их полные определения. Переменные, объявленные внутри класса, принадлежат этому классу. Идентификаторы переменных и функций внутри класса застрахованы от конфликтов с идентификаторами других классов.

Для идентификаторов класса применимы те же правила, что и для остальных типов или имен переменных. В C++ для идентификаторов предельная длина не определена, но в Borland C++ максимальная длина равна 32 сим­волам. Количество значащих символов можно указать в диалоговом окне, которое появляется при выполнении по­следовательности команд Options|Project|+Conipiler|Source. По умолчанию все 32 символа являются значащими. Написание букв (строчная или прописная) весьма важно. В Borland C++ принято, писать идентификаторы классов и глобальных структур с прописной буквы. Класс class counter {…}; определяет еще один класс, идентичный (за исключением имени) классу Counter. Объявление двух классов с оди­наковыми именами недопустимо, независимо от того, идентичны объявления или нет.

Переменная count определена внутри класса. Таким образом, count — это переменная-чпен (member variable) класса. Любая переменная, определенная в классе, имеет область видимости класса (class scope). Область видимос­ти переменной-члена (не применима в ANSI С) простирается от точки объявления переменной до конца объявления класса.

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

Класс Counter содержит объявление функций SetValue (long) и GetValue (), которые называются функ­циями-членами (member function) класса. Эти функции пока не определены, они только объявлены. Реальное их определение для класса Counter было опущено и приводится только сейчас:

void Counter::Setvalue(long value)

{count = value;}

long Counter::GetValue()

{return count;}

При определении функции-члена после типа возвращаемого значения нужно всегда указывать, членом какого класса является функция. Для этого нужно написать имя класса и поставить за ним два двоеточия. Как и другие функции в C++, функции-члены должны быть объявлены до использования. Объявление должно быть полным, включая тип возвращаемого значения и типы аргументов. В C++ типы аргументов функции должны быть объяв­лены одновременно с функцией-членом с помощью следующей записи:int foo (int parm1, long parm2) ;

Для того чтобы использовать класс, нужно определить объект этого класса. Объек­ты класса определяются точно так же, как структурные или скалярные переменные. Чтобы определить переменную people типа Counter, используйте следующую запись:Counter people;

Объекты классов, определяемые внутри функции, используют ту же запись, что и другие типизированные пере­менные. Область видимости этих объектов начинается в точке объявления и заканчивается в конце блока. Объект people имеет класс памяти auto и хранится в кадре стека (stack frame).

Для вызова функции-члена объекта класса используется та же запись, что и для обращения к элементу структу­ры: за точкой следует имя элемента. В остальном использование функций-членов ничем не отличается от использо­вания традиционных функций С. В функциях-членах используются скобки, в переменных-членах — нет.

2 Управление доступом к классу

Класс включает как данные, так и код. Доступ к элементам класса управляем. Это управление ка­сается не только данных, но и кода. Объявление класса должно предшествовать использованию класса. Пользователю предоставляется описание класса, но не обязательно его внутренняя реализация. Насколько это касается пользователя, внутренние детали класса ему не важны и знать их вовсе не обязательно. Более того, чем меньше пользователю нужно знать о "внутренностях" класса, тем лучше. На такую концепцию часто ссылаются как на со­крытие информации (information hiding).

Однако, чтобы использовать класс, нужно знать, какие функции можно использовать, и какие данные доступны. Набор используемых функций и доступных данных называется пользова­тельским интерфейсом класса. Интерфейс — это как поверхность трехмерного предмета, граница между предме­том и остальным миром. Знание пользовательского интерфейса класса — это то, что математики называют необхо­димым и достаточным условием использования класса. Пользовательский интерфейс сообщает вам, как класс себя ведет, а не как он устроен. Вам не надо знать, как реализован класс, и это уменьшает объем отслеживаемой инфор­мации при разработке проекта. Как только класс создан и отлажен, он готов к работе и может использоваться мно­го раз. С точки зрения пользователя, класс — это черный ящик с характерным поведением.

Главная забота класса — скрыть как можно больше информации. Это накладывает определенные ограничения на использование данных или кода внутри класса. Существует три вида пользователей класса:

• сам класс • обычные пользователи • производные классы

Каждый пользователь обладает разными привилегиями доступа. Каждый уровень привилегий доступа ассоциируется с определенным ключевым словом. Поскольку уровней привилегий доступа всего три, ключевых слов тоже три:

private

public

protected

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

class AccessControlExample {

int value_l; // приватный по умолчанию

void f_l(long); // приватный по умолчанию

private:

int value 2; // по-прежнему приватный

int f_2(char*); // приватный

public:

char* value_3; // общедоступный

long f_3 (); // общедоступный

protected:

int value 4; // защищенный void

f_4 (long); // защищенный };

Любое объявление, появляющееся до ключевого слова управления доступом, считается приватным по умолчанию. В приведенном примере переменная value_l и функция f_l (long) являются приватными. В нем есть и явное объявление private. Этот пример иллюстрирует интересную особенность: разделы с разными привилегиями доступа появляются в любом порядке и в любом количестве. Класс AccessControlExample можно объявить следующим образом:

class AccessControlExample {

private: int value_l; // приватный

private: void f_l(long); // приватный

private: int value_2; // приватный

private: int f_2(char*); // приватный

public: char* value_3; // общедоступный

public: long f_3; // общедоступный

protected: int value_4; // защищенный

protected: void f_4(long); // защищенный

};

Последний пример вполне приемлем для C++, но столь многословен, что почти никогда не используется.

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

Например, преобразовав указатель на объект класса в указатель на unsigned char, можно получить доступ ко всему содержимому объекта, включая и приватные, и общедоступные части. Подобное возможно только в экстраординарных случаях, например при реализации отладчика, но не при обычном кодировании.

В крайнем случае можно объявить все содержимое класса общедоступным и манипулировать им, как заблагорассудится. Контроль доступа в C++ введен в целях уменьшения ошибок и усиления последовательности в разработке, но не для предотвращения "взлома".

Классы нужны для использования в программах. Следовательно, в каждом из них должен быть хотя бы один член с уровнем привилегий доступа, отличным от приватного.

3 Область видимости класса

C++ вводит новую область видимости для идентификаторов, объявленных внутри класса. Такие идентифика­торы видимы только в сочетании с объектами класса. При неоднозначном толковании должен использоваться опе­ратор разрешения области видимости ::.

Пустые классы

Несмотря на то, что назначение класса — инкапсуляция кода и данных, он может быть пустым: class Empty {};

Сделать много с таким классом вам не удастся, но можно создать объект класса Empty:

void main ( )

{Empty object;}

Зачем нужен пустой класс? Часто при разработке большого проекта нужно протестировать его раннюю версию, в которой некоторые классы еще до конца не разработаны и не реализованы. Вместо них используются так называемые заглушки, разработанные таким образом, чтобы компилятор не выдавал ошибок и можно было проверить уже написанную часть кода.

Вложенные классы

Класс, объявленный внутри объявления другого класса, называется вложенным и может рассматри­ваться как класс-член (member class). Рассмотрим пример вложенного класса:

class Outer { public:

class Inner {

public:

int x;};};

Класс Inner называется вложенным по отношению к Outer. Объявление такого класса не выделяет памяти для объекта этого класса. Вложенное объявление влияет только на область видимости имени вложенного класса, а память выделяется только при создании экземпляра класса.

Правила доступа для вложенных классов

В AT&T версии 3.0 и в Borland C++ 4.5 вложенный класс никакими особыми привилегиями доступа по отноше­нию к членам включающего класса не обладает. И точно так же включающий класс не обладает особыми привиле­гиями доступа по отношению к членам вложенного класса. Вложение распространяется только на область види­мости имени класса.

К идентификатору вложенного класса применяются те же правила, что и к другим данным-членам. Если вло­женный класс объявлен в секции private включающего класса, то его смогут использовать только данные-члены включающего класса. Включающий класс имеет доступ к имени вложенного класса без разрешения области види­мости.

Основная причина использования вложенных классов состоит в уменьшении количества глобальных идентифи­каторов. Если класс используется исключительно для реализации другого класса, было бы неплохо сделать его вложенным, избегая при этом добавления еще одного глобального имени.

Вложенный класс имеет доступ ко всем обычным нестатическим членам включающего класса только через ука­затели или ссылки.

Создание экземпляра класса

Класс не является физической сущностью, он сродни объявлению структуры. Память выделяется только тогда, когда класс используется для создания объекта. Этот процесс называется созданием экземпляра класса.

Неполные объявления классов

Класс должен быть объявлен до использования его членов. Однако иногда класс используется как единое целое, без обращения к его членам. Рассмотрим пример — объявление указателя на класс — в следующем коде:

MembersOnly* club;

Соседние файлы в папке Zaochniki