|
Программирование >> Унарные и бинарные операторы
Но почему же тогда работала программа из листинга 7.2, ведь там тоже использовалось объявление myclcKk а, а в описании классаmyclock вообще ие было конструкторов? Все дело в том, что классы без конструктора компилятор C+-I- считает бедными и снабжает их социальной помощью - специальным конструктором, который, правда, ничего не делает, но исправно вызывается при каждом объявлении объекта. Если же компилятор видит хотя бы один конструктор, то считает, что класс вырвался из нищеты и должен заботиться о себе сам. Теперь конструктор, вызываемый по умолчанию при объявлении объекта, нужно создавать самому. Простейп!ий конструктор для нащих часов может выглядеть так: class myclоск{ public: myclock(){min-hour-sec=0:} Г Он, как видим, не имеет параметров, и поэтому будет вызываться при объявлении объекта (myclock а:). В отличие от конструктора, предоставляемого бедным классам, этот действует: он устанавливает нулевое время. Ее ли же переменная объявляется как туе 1 оск а (И. О. О), вызывается другой конструктор, и отсчет времени начинается с одиннадцати часов. Ну а если объявить переменную как а( 11.0), компилятор сообщит об ошибке: конструктора с двумя целочисленными параметрами в описании класса нет. Завершим этот раздел маленьким открытием: оказывается, конструкторы есть абсолютно у всех объектов С++, даже таких примитивных, как целочисленные Видимость Казалось бы, объявление объекта - очень простое действие. Записав myclock а, мы командуем компилятору вызвать при создании объекта конструктор по умолчанию (тот, у которого лет параметров). Но когда и сколько раз создается объект - зависит от места, где он объявлен. Значит, для понимания работы конструктора необходимо познакомиться с общей структурой программы. Итак, программа на С++ состоит из обязательной функции main() и всего остального (листинг 8.3). Листинг 8.3 #include <iostreara> #include myclock2.h myclock a: void nonsense(){ a.dispO: cout endl: } int main(){ nonsenseC): a.dispO: cout endl: return 0: Прежде всего обратите внимание на включаемый файл myclock2.h, содержащий определение класса туе lock с двумя конструкторами - один вызывается по умолчанию и устанавливает нулевое время, второй имеет три параметра и способен задать любое время. Теперь посмотрим на листинг 8.3. В нем объект а типа myclock объявляется вне функции mainO и вне функции переменные (типа int). Начальное значение переменной можно указать в скобках, потому что у нее, как и у всякого объекта, есть конструктор: int i(5): nonsenseO. Начальное время при этом пе указывается, значит, при создании объекта будет вызван конструктор по умолчанию и время станет нулевым (00 часов 00 минут 00 секунд). Объект а тина myclock, о котором мы сейчас говорим, называется глобальным, потому что он виден из любого места программы. При создании глобальных объектов конструктор вызывается только один раз - enie до вызова функции mainO. Глобальный объект а типа myclock видят и функция nonsenseO, и функция mainO (см. листинг 8.3), поэтому па экран дважды, будет выведено одно и то же время: 00:00:00 00:00:00 А теперь посмотрим на профамму, показанную в листинге 8.4. Листинг 8.4 include <iostream> #include myclockZ.h myclock a: void nonsenseO{ a.dispO: cout endl: } int mainO{ myclock 3(10.59.59): nonsenseO: 00:00:00 a.dispO: cout endl: 10:59:59 ::a.disp(); cout endl: 00:00:00 return 0: В этой профамме объявляются два объекта myclock, один - вне функции mainO, Другой - внутри. Имена обоих объектов одинаковы, но для инициализации первого используется конструктор по умолчанию, время вторых часов (без секунды оди!П1адцать) устанавливается другим конструктором. Задача 8.1. Как доказать, что глобальный объект создается еще до вызова функции mainO? Раз в профамме объявлены два объекта с одним именем, то непонятно, какое время будет показано после вы.зова ()ункции nonsenseO, а какое - после выполнения слсдуюп1ей инструкции - вызова функции a.dispO? Что касается пашей функции nonsenseO, то ей виден только глобальный объект clock, значит, инструкция a.dispO внутри функции nonsenseO выведет на экран время 00:00:00, задаваемое конструктором по умолчанию. А вот внутри функции mainO объявлен локальный объект myclock а(10.59.59) и получается, что функции main() доступны два одноименных объекта, причем один показывает 00:00:00, а второй - 10:59:59. Какое же время появится наэкране? Запуск программы показал, что это время - без секунды одиннадцать. То есть из двух одноименных объектов функция предпочигаег локальный. Но это пе значит, что глобальный объект перестал для нее существовать. Чтобы получить доступ к нему, достаточно нос ганить перед его именем пару двоеточий, называемую оператором распшрсния области видимости. Мы уже встречались с ним при определении собственных функций вне класса. Чтобы показать, что функция setO принадлежит классу myclock, нужно поставить перед именем функции префикс mycl оск::. Когда же объект глобален, перед двоеточием ставить нечего, поэтому пишут просто ::a.set(), и это значит, что имеется в виду объект, определенный вне функции mainO и вообще вне любой функции. Теперь нам ясно, что профамма, показа!И1ая в листинге 8.4, выведет на экран три значения времени: 00:00:00 10:59:59 00:00:00 В отличие от глобальных, локальные объекты, определенные внутри функции, создаются при каждом ее вызове. Но когда происходит возврат из функции, такой объект перестает существовать, а при следующем вызове создается вновь. Естественно, конструктор такого объекта вызывается при каждом его создании, то есть при каждом вызове функции. Правда, локальный объект, объявленный внутри mainO, чаще всего создается один раз и один раз (перед заверщением программы) уничтожается. Это происходит потому, что функция main() вызывается, как правило, только однажды. Кроме локальных и глобальных существуют еще статические объекты, которые создаются один раз (соответственно, и конструктор таких объектов вызывается один раз) и помнят свое прежнее состояние. Чтобы лучще понять, о чем идет речь, посмотрим на программу, показанную в листинге 8.5. Листинг 8.5 #1nclude <iostream> using namespace std: void nonsense){ int i: static int j: cout 1= 1 endl: cout j= j endl: i-l:j-3: } int main(){ nonsense): i=? j=0 nonsense): i=? j=3 return 0: Чаще всего такой объект уничтожается автоматически, но иногда нужно создать специальную функцию - деструктор, о которой мы поговорим в следуюи1ем разделе. Локальные объекты называют еще автоматическими, потому что они автоматически создаются при каждом вызове функции. При первом вызове функции nonsense() обычная переменная i содержит мусор , то есть то, что было в памяти компьютера до того, как ее заняла переменная. В отличие от i, статическая переменная j содержит ноль, то есть все ее биты равны нулю. После выполнения инструкций i-1 и j=3 обе переменные получают определенные значения, но после выхода из функции значение автоматической переменной i забывается, а значение статической j - нет. И при следующем вызове функции nonsenseC) значение i может быть каким угодно, в том числе 1, азначение j гарантированно равно 3. Переходя от простых целочисленных переменных к объектам, заметим, что статический объект создастся всего один раз, потому и конструктор его работает только при первом вызове функции. Дестру1аоры я тебя породил, я тебя и убью! . В. Гоголь, *Тарас Бульба Создавая новые объекты, мы надеялись, что они будут правильно и своевременно уничтожены. До сих пор эти надежды оправдывались, потому что объекты, состоящие из стандартных переменных типа int, double, string, а также массивов, уничтожаются автоматически, например при выходе из функции. Сделать это легко, потому что такие объекты состоят либо из переменных заранее известного размера (таких, как int, double или массивы), либо из стандартных объектов (таких, как string), уже способных к самоуничтожению. Но стоит создать более сложный объект, чей размер определяется во время исполнения программы (то есть
|
© 2006 - 2024 pmbk.ru. Генерация страницы: 0
При копировании материалов приветствуются ссылки. |