Конструкторы и деструктор
Методы класса
Разработка класса в ООП.
Класс - определяемый пользователем тип. Работа с классами, как и с базовыми типами, определенными в языке, состоит из нескольких этапов:
· определение класса (для определенных в языке типов не требуется);
· создание объектов (экземпляров) класса;
· работа с объектами (экземплярами) класса;
· уничтожение объектов (экземпляров) класса после использования.
Концепция классов предназначена для того, чтобы предоставить программисту инструмент для создания новых типов, столь же удобных в обращении, сколь и встроенные типы. В идеале тип, определяемый пользователем, должен отличаться от встроенных типов не способом использования, а только способом создания.
Способы создания и уничтожения объектов и работа с ними задаются в определении класса. Определение класса предполагает выполнение двух шагов: сначала определяется интерфейс (описание) класса, а затем разрабатывается конкретная реализация класса.
Определение интерфейса класса включает в себя:
· определение имени класса ( определяет новый тип; абстракция, с которой будем иметь дело);
· определение состояния класса (состав, типы и имена полей в классе, предназначенных для хранения информации, а также уровни их защиты); данные, определяющие состояние класса, получили название членов-данных класса;
· определение методов класса (определение прототипов функций, которые обеспечат необходимую обработку информации). На этом этапе - словесное описание того, что мы хотим получить от класса, не указывая, как мы этого добьемся.
Определение класса:
Шаги | Состав класса | Внешнее проявление |
интерфейс (описание) | - объявление полей данных | экземпляры переменных объектов класса, хранящие соответствующую информацию |
реализация | - прототипы функций - определение функций | методы для обработки сообщений, передаваемых объектам класса |
Пример определения интерфейса класса:
Класс “рациональная дробь” - Rational [‘рэшенел].
Состояние класса: числитель и знаменатель дроби; два поля типа “целое”, с именами num (от numerator [‘нью:мерэйте] - числитель) и den (от denominator [ди’номенэйте] - знаменатель). Пока ограничиваемся диапазоном представления в стандартных типах. Защита: знаменатель не должен быть равным нулю ни при каких условиях (для удобства обработки полагаем всегда знаменатель >0); поля класса не должны быть доступны извне класса не предусмотренными классом способами.
Методы класса: традиционные арифметические операции (сложение дробей - a/b + c/d = (a*d + c*b)/(b*d), затем требуется сократить дробь; умножение и т.п.); вывод значения дроби - в виде a / b, если b 1; в противном случае просто a; и т.п. На этапе определения методов могут появиться вспомогательные методы (типа сокращения дробей), которые явно не следуют из постановки задачи. Эти вспомогательные методы, как правило, не должны быть доступны извне класса.
Далее это словесное описание класса следует переложить на конкретный язык программирования - в нашем случае С++.
6. Определение класса в С++
Существует много способов размещения различных частей класса. Рекомендуется интерфейс (описание) класса размещать в отдельном файле-заголовке, а определение функций класса (часть реализации) - в одном или нескольких компилируемых исходных файлах. В некоторых ситуациях оправдано совмещать прототипы функций с их определением.
Для определения класса - специальное ключевое слово class, но можно и традиционное struct. Отличия между ними - чуть позднее.
Структура определения класса: или
class имя_класса{ struct имя_класса{
уровень_видимости: уровень_видимости:
определения_данных определения_данных
прототипы_функций-методов_класса прототипы_функций-методов_класса
уровень_видимости: уровень_видимости:
. . . . . .
}; };
Уровни видимости разделяют определение класса на несколько частей. В каждой части класса располагаются члены класса - определения данных (члены-данные) и/или прототипы функций (функции-члены; возможно также определение прототипов функций-друзей класса, которые не являются членами класса, но входят в интерфейс класса).
7. Уровни видимости
Уровень_видимости задается одним из трех ключевых слов: private[‘прайвит], protected[прэ’тэктид], public[‘паблик]. Порядок следования их произволен, они могут появляться неоднократно или отсутствовать в определении класса. Область действия каждой части продолжается до тех пор, пока в определении класса не появится метка другой части или не будет обнаружен конец описания класса.
· private - определяет закрытую часть класса, недоступную извне класса.
· protected - пока для нас аналогичен private; различия между ними проявляются при использовании наследования.
члены класса, помещенные в закрытую или защищенную части класса, доступны только изнутри класса (т.е. из функций-членов класса).
· public - определяет открытую часть класса, видимую и доступную извне класса.
Методы класса определены для класса, предназначены для обработки информации, определяющей состояние класса, поэтому всегда видят все его части.
Пример определения класса на языке C++:
а) с использованием class б) с использованием struct
class X{ struct X{
private: private:
. . . a1 . . . . . . a1 . . .
protected: protected:
. . . a2 . . . . . . a2 . . .
public: public:
. . . a3 . . . . . . a3 . . .
. . . f() . . . . . . f() . . .
}; };
Объявляем данное типа (нового) X - в соответствии с обычными правилами (не зависимо от того, как определен класс - с помощью class или struct):
X obj;
Доступ к членам класса записывается в соответствии с общими синтаксическими правилами языка С аналогично доступу к членам структуры - через операцию “точка” (например, obj.a2 или obj.f()), но результат будет зависеть от уровней видимости частей класса.
Так, конструкции obj.a1, obj.a2 - вызовут сообщения об ошибке (члены класса a1 и a2 не видны (не доступны) извне класса); obj.a3, obj.f() - корректны. Внутри функции - метода класса f() можно без опасений использовать все имена: a1, a2, a3 и f().
Если в начале определения класса отсутствует указание уровня видимости: class A{... x ...}; или struct A{ ... x ... };, то:
· для class принимается private: class A{private: ... x ...};;
· для struct принимается public: struct A{ public: ... x ... };.
Рекомендации по поводу использования уровней видимости при определении класса.
Описания_полей_класса и прототипы_функций определяются в соответствии с обычными правилами С (С++).
Два способа классификации методов класса:
А) По функциональному назначению:
- конструкторы - для создания экземпляров класса
- деструкторы - для уничтожения экземпляров класса
- селекторы - обработка состояния класса без его изменения
- модификаторы - изменение состояния класса
- итераторы - последовательный доступ к элементам данных, определяющих состояние класса
Б) По организации доступа к закрытой и защищенной частям класса:
- функция-член класса - функция, принадлежащая самому классу и не существующая вне класса
- функция-друг класса - внешняя по отношению к классу функция, которая может существовать вне класса, но имеет доступ к закрытой (и защищенной) части класса
Пока используем только функции-члены класса.
Конструкторы и деструктор класса имеют специфический синтаксис, другие методы класса - обычный.
Конструкторы служат для создания экземпляров класса; при этом могут выполнять выделение памяти и инициализацию состояния класса. Если создаются статические данные, память под которые выделяется на этапе компиляции, тогда конструкторы могут только инициализировать состояние класса.
Если для класса существует хотя бы один конструктор, он вызывается каждый раз при создании экземпляра класса. Конструктор вызывается везде, где создается экземпляр класса (объявление объекта, динамическое размещение объекта, передача аргументов в функцию, возвращение функцией значения).
Типы конструкторов (в зависимости от следующих условий):
А) Что они делают (как выполняют инициализацию состояния класса):
- пустой конструктор,
- инициализирующие конструкторы,
- копирующий конструктор.
Б) Кто их определяет:
- конструкторы по умолчанию - только пустой и копирующий. Пустой конструктор по умолчанию только создает экземпляр класса, но не инициальзирует его.
- явно определенные программистом - любые.
В определении класса не обязательно должны быть использованы все три типа конструкторов - все определяется конкретной задачей. В классе может быть определено несколько конструкторов. Если есть хотя бы один инициализирующий конструктор, определенный программистом, пустой конструктор по умолчанию не используется (даже если программист не определил собственный пустой конструктор). Если отсутствует определенный пользователем копирующий конструктор, будет использоваться копирующий конструктор по умолчанию.
Деструктор служит для разрушения экземпляра класса. Может быть определен только один деструктор. Также существуют деструктор по умолчанию или явно определенный программистом.