Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология Образование Политология Производство Психология Стандартизация Технологии |
Создание и удаление объектов: конструктор и деструктор
Создание объектов конструкторов Что такое деструктор
бъекты в программе создаются и уничтожаются так же, как и объекты реального мира. Если класс сам отвечает за свое существование, он должен обладать возмож- ностью процессом уничтожения и создания объектов. Программистам на C++ повезло, поскольку C++ предоставляет необходимый для этого механизм (хотя, скорее всего, это не а результат разумного планирования языка). Прежде чем начинать соз- давать и уничтожать объекты в программе, обсудим, что значит "создавать объекты".
Создание Некоторые подчас теряются в терминах класс и объект. В чем разница между эти- ми терминами? Как они связаны? Я могу создать класс который будет описывать соответствующие свойства лучшего друга человека. К примеру, у меня есть две собаки. Это значит, что мой класс Dog содержит два экземпляра Труди и Скутер что два: Скутера я не видел уже несколько дней...). Класс описывает тип предмета, а объект является экземпляром класса. Dog является классом, а Труди и Скутер объектами. Каждая собака представляет собой отдельный объект, но существует только один класс Dog, при этом не имеет значения, сколько у меня собак. Объекты могут создаваться и уничтожаться, а классы попросту существуют. Мои соба- ки Труди и Скутер приходят и уходят, а класс Dog (оставим эволюцию в стороне) вечен. Различные типы объектов создаются в разное время. Когда программа начинает выполняться, создаются глобальные объекты. Локальные объекты создаются, когда программа сталкивается с их объявлением. Глобальный объект является объектом, объявленным вне каких-либо функций. Локальный объект объявляется внутри функции, а но, является локальным для функции. В приведенном ниже примере пе- ременная является глобальной, а переменная — локальной по отношению к (). int void pickOne <
Глава17.Создание иудалениеобъектов:конструкторидеструктор177 Согласно правилам С глобальные объекты по умолчанию инициализиру- ются нулевыми значениями- Локальные объекты, т.е. объекты, ные внутри функций, не имеют инициализирующих значений. Такой подход, вообще говоря, для классов неприемлем. C++ позволяет определить внутри класса специальную функцию-член, которая ав- томатически вызывается при создании объекта этого класса. Эта функция-член назы- вается конструктором и инициализирует объект, приводя его в некоторое необходи- мое начальное состояние. Кроме конструктора, в классе можно определить деструк- тор, который будет вызываться при уничтожении объекта. Эти две функции и являются предметом обсуждения данной главы.
Конструктор — это функция-член, которая автоматически во время соз- дания объекта соответствующего класса. Основной задачей конструктора является ини- циализация объекта, приводящая его в некоторое корректное начальное состояние.
Зачем нужны конструкторы Объект можно проинициализировать на этапе его объявления, как сделал бы про- граммист на С: struct Student {
} void {
}
float gpa;
Student s // функции... Этот фрагмент кода не будет работать для настоящего класса C++, поскольку внешнее приложение не имеет доступа к защищенным членам класса. Приведенный ниже фрагмент некорректен. class Student {
// члены...
int
};
gpa; void { Student s = // неправильно, так как // недоступны // функции...
В данном случае функция не член п () не имеет права обращаться к членам и поскольку они являются защищенными (а функция не объяв- лена в качестве друга класса).
178 Часть ///. "Классическое" программирование Однако, как уже отмечалось, вы можете обеспечить класс инициализирующей функцией, которая будет вызываться в процессе создания объекта. Поскольку эта функция является членом класса, она имеет доступ к защищенным членам. Такой способ инициализации продемонстрирован в приведенном ниже примере. class
public: void {
}
gpa 0.0;
= 0; // открытые члены... protected:
float gpa; }; void () { Student s; // создаем объект ... s.init{); // ... и инициализируем его // функции... } Однако при таком подходе ответственность за инициализацию объекта снимается с класса. Другими словами, класс должен полагаться на то, что внешнее приложение вызовет функцию-член ini t (). В противном случае объект останется не лизированным и будет содержать непредсказуемые значения. Для того чтобы избежать этой неприятности, ответственность за вызов инициали- зирующей объект функции необходимо переложить с приложения на компилятор. Всякий раз при создании объекта компилятор может вставлять в код специальную инициализирующую функцию — а это и есть конструктор! Работа с конструкторами Конструктор ~ это специальная функция-член, которая автоматически вызы- вается во время создания объекта. Конструктор должен иметь то же имя, что и класс. (Таким образом компилятор сможет определить, что именно эта функ- ция-член является конструктором. Конечно, создатели C++ могли сформулиро- вать это правило как угодно, например, так: "Конструктором является функция с именем Как именно определено правило, не имеет значения; глав- ное — чтобы конструктор мог быть распознан компилятором.) Еще одним свойст- вом конструктора является то, что он не возвращает никакого значения, посколь- ку вызывается автоматически (если бы конструктор и возвращал значение, его все равно некуда было бы записать). Класс с использованием конструктора продемонстрирован в следующем примере:
class !
Student() { << "Конструируем объект Student\n"; semesterHours = 0; gpa = 0.0;
Глава17.Создание иудалениеобъектов:конструкторидеструктор179 // члены...
int float gpa;
s; // создаем и инициализируем объект // функции... } В этом примере компилятор сам вызывает конструктор (] в том месте, где объявляется объект s. Этот простой конструктор реализован в виде встроенной (inline) функции. Конст- руктор можно создать и как обычную функцию с телом, вынесенным из объявления класса:
class Student {
// открытые члены...
int float gpa; i Student: О ( cout << "Конструируем semesterHours = gpa = 0.0;
(] { Student s; // создаем и инициализируем объект // функции... int char* { fn(); return 0;
В данном примере добавлена небольшая функция чтобы эту тестовую программу можно было запустить. Настоятельно рекомендую пройти эту программу в пошаговом режиме отладчика перед тем, как двигаться дальше. Инструкции по работе с отладчиком C++ приведены в главе 29, способов избежать ошибок". Выполняя этот пример в пошаговом режиме, дойдите до строки с объявлением объекта s. Выполните команду отладчика Шаг с заходом в функции (Step into), и управ- ление как по волшебству перейдет к () (если у вас inline-версия конструктора, убедитесь, что при компиляции включена опция Outline inline functions, с помощью которой тело функции выносится из объявления класса; в противном случае код конструктора будет подставлен в тело программы и вы не смо- жете попасть в конструктор). Продолжайте выполнение конструктора в пошаговом режиме. Когда функция закончится, управление перейдет к следующей за объявлени- ем объекта класса строке.
180 Часть ///. "Классическое" программирование В одной может быть объявлено объектов. Выполните, например, о пошаговом режиме следующее: f. n
s [5]; //создаем массив объектов
} Вы увидите пять вызовов конструктора — по одному для каждого элемента массива.
В приведенной далее программе используются команды вывода сообще- информирующие о вызове конструктора, на случай, если вы не мо- жете (или не хотите) запустить отладчик. Эффект будет хотя и не столь впечатляющим, но от этого не менее убедительным. Конструктор может быть запущен только автоматически! Нельзя вызывать конст- руктор как обычную функцию-член, а значит, и повторно инициализировать объект класса
{ // создаем и инициализируем // функции... s . () ; // его, // но компилятор сообщит об } Объявление конструктора не должно содержать тип возвращаемого значения — и даже тип Если класс имеет которые являются объектами другого класса, конструкторы для этих объектов также будут вызваны автоматически. Обратите вни- мание на следующий пример, в который добавлены команды вывода сообщений, по- зволяющие увидеть, в каком порядке создаются объекты: induc e h> clas s Student { public : () { << "Конструируем
gpa = 0.0; ) // открытые члены... protected:
}; class
<< "Конструируем Teacher\n";
class
Глава 17. Создание и удаление объектов: конструктор и деструктор 181 public:
{ cout << "Конструируем TutorPair\n"; = )
Teacher teacher; int
int argc, char* { TutorPair tp; << "Возвращаемся в return 0; } В результате работы этой программы на экран будут выведены следующие со- общения: Конструируем Конструируем Teacher Конструируем TutorPair Возвращаемся в Создание объекта tp в main;) вызывает конструктор TutorPai r автоматически. Перед тем как управление будет передано телу конструктора TutorPair , вызываются конструкторы для studen t и teacher . Конструктор studen t вызывается первым, поскольку объект этого класса объявлен первым. Затем вызывается конструктор Teacher. И только после создания этих объ- ектов управление переходит к конструктору класса TutorPair , который теперь может конструировать оставшуюся часть объекта. Это не означает, что TutorPai r отвечает за инициализацию объектов studen t и teacher . Каждый класс отвечает за инициализацию своего объекта, где бы тот не создавался.
Объекты класса уничтожаются так же, как и создаются. Если класс может иметь конструктор для выполнения начальных установок, то он может содержать и специальную функцию для уничтожения объекта. Такая функция-член называ- ется деструктором. Зачем нужен деструктор Класс может затребовать для своего объекта некоторые ресурсы с помощью конст- руктора; эти ресурсы должны быть освобождены при уничтожении объекта. Напри- мер, если конструктор открывает файл, перед окончанием работы с объектом класса или программы этот файл следует закрыть. Возможен и другой вариант: если конст- руктор берет память из кучи, то она должна быть освобождена перед тем, как объект перестанет существовать. Деструктор позволяет делать это автоматически, не полага- ясь на вызов необходимых функций-членов в программе.
182 Часть программирование Работа с деструкторами Деструктор имеет то же имя, что и класс, но только с предшествующим ему сим- волом тильды (-) (C++ последователен и здесь: ведь символ тильды не что иное, как символ оператора "нет", т.е. деструктор — это отрицание конструктора). Как и конст- руктор, деструктор не типа возвращаемого значения. С учетом сказанного дест- руктор класса Student будет выглядеть так: class {
Stucent() { = 0; gpa = 0.0; } () { //любые ресурсы освобождаются здесь } // открытые члены...
int gpa; } ; Деструктор вызывается автоматически, когда объект уничтожается или, если гово- рить языком C++, происходит его деструкция. Чтобы избежать тавтологии ("деструктор вызывается для деструкции объекта"), я по возможности старался не применять этот термин. Можно также сказать "когда объект выходит из области ви- димости". Локальный объект выходит из области видимости, когда функция, создав- шая его, доходит до команды return . Глобальный или статический объект выходит из области видимости, когда прекращается работа программы. Если уничтожается более одного объекта, деструкторы вызываются в порядке, об- ратном вызову конструкторов. То же касается и случая, когда уничтожаемый объект содержит Далее приведена программа TutorPair , использующая де- структоры. <stdio.h> < ream. class Student
{ cout << "Конструируем semesterHours = gpa = 0.0; }
{ cout << "Уничтожаем Student\n"; } // открытые члены... protected: int: semesterHours ; float gpa;
Глава17.Создание иудалениеобъектов:конструкторидеструктор183 class Teacher
Teacher() cout « "Конструируем Teacher\n";
cout << "Уничтожаем Teacher\n"; class TutorPair iс:
cout << "Конструируем Tutor?air\n";
cout << "Уничтожаем TutorPairW ; protected: Teacher i. nt ; }; in t (in t char * pArgs [ ] )
TutorPair tp; cout << "Возвращаемся в return 0;
Если вы запустите эту профамму, на экран будуг выведены следующие сообщения:
Конструируем Teacher Конструируем TutorPai r Возвращаемся в Уничтожаем Уничтожаем Уничтожаем Student Как видите, конструктор класса TutorPai r вызывается при объявлении tp , а дест- руктор — перед завершающей скобкой функции . Порядок вызова деструкто- ров порядку вызова конструкторов.
184 Часть "Классическое" программирование Глава |
Последнее изменение этой страницы: 2019-04-19; Просмотров: 251; Нарушение авторского права страницы