Т. Пратт, М. Зелковиц - Языки программирования - разработка и реализация (4-е издание_ 2002) (1160801), страница 164
Текст из файла (страница 164)
Класс ОаСа5Соге является производным от класса РатаСопчег~. Функция сопчегг., объявленная в классе ОахаСопчегь (записанная в виде Оз гаСопчегт:: соя хегс), видна в этом определении класса. Строка 7. Ключевое слово роЫ ~ с (открытый) означает, что объявления в строках с 8-й но 19-ю видны вне онределения класса. Строки 11 — 12. Класс Оатз5гоге создает абстракцию данных для хранимых данных, инкапсулируя фактические значения данных в массив, который не виден вне определения класса.
Строка 13. Фуокция зе~рг~ пь возврашает число элементов, которые нужно напечатать, а затем многократно вызывается рг~ птлЫ для последовательного вывода на печать значений. Строка 14. Функция рг~ в~и! возвращает следуюшее значение из массива. Эту функцию необходимо вызывать, поскольку массив згоге инкапсулирован в классе Оаха5тоге и доступ к нему имеют только функции, определенные в данном классе.
Если бы массив згоге был открытым, то не требовалось бы использовать эту функцию. Строка 20. Все объявления, которые следуют за ключевым словом рг1 чате, будут закрытыми и могут использоваться только внутри определения этого класса. Строка 25. Начало основной программы кю и. Строки 26-27. Переменные Р и ~ являются локальными. Объект х класса Озга5гоге является нашим объектом для хранения массива. Строка 28, Эта строка аналогична строке 6 листинга ПА.
Последовательность действий следующая: 1) для возврата одиночного символа вызывается функция Рег класса с1п, определенного в заголовочном файле йгеаш. Ь; 2) для преобразования размера массива и сохранения этого значения в переменной х.иае вызывается функция Оа1а5гоге:: ю~т~а1 (строка 8); 3) размер массива устанавливается равным ~, и если х ие равно О, то осуществляется обработка массива. Строка 29.
Оператор 1аг вызывает функцию Рет для чтения каждого вводимого пользователем числа в массиве и сохраняет его в х. зтоге посредством вызова функции ОаСа5Согег:эа~е, Строка 30. Функция Рага5Тоге::зе1ргш1 инициализирует оператор 1ог, который последовательно уменьшает значение счетчика цикла до 0 и выводит на печать каждый элемент массива посредством вызова функции Оата5тоге: . рг~пгхай 594 Приложение. Обзоры языков Потоковая функция соос осуществляет конвейерную пересылку данных в функцию. Таким образом, чтобы напечатать а, Ь и с, необходимо написать либо: сонг « а Ь с либо сопс « а соос « Ь соот « с Стлрока 3 б С помощью вызова функции бата ото ге: эопт на печать выводится сумма массива.
Объект епд1, который по конвейеру передает функция сооЬ, добавляет символ конца строки и выводит строку на печать. Строка 32, Функция оеЬ класса от п вызывается в цикле до тех пор, пока не встретится символ конца строки 1п. Это необходимо для того, чтобы пропустить весь ввод пользователя в строке, когда уже прочитаны все элементы обрабатываемого массива. П.З.1. Объекты данных Элементарные данные в языке С++ такие же, как н в языке С. Элементарные типы данных Так же как и в языке С, в С++ используются элементарные типы тпо и Поз~.
Определяемые пользователем типы помимо тпь и т1оа1, для создания структурных объектов в программе можно использовать такие конструкции языка С, как етгост и туредеб Кроме того, в языке С++ существует возможность опрсделять классы с помощью конструкции с1аез, которая является расширением етгос~ за счет добавления дополнительных компонентов структуры — подпрограмм (тиетодоо). Синтаксис описания класса приведен ниже: с1не ння класса (компонент класса,: компонент класса,. компонент класса„. ] Здесь каждый компонент класса является либо объявлением объекта данных, либо объявлением метода. Обьявленил обьектлов данных могут быть либо объявлениями сонет, либо объявлениями структур еЬгпсс, либо объявлениями объектов данных любого типа или класса.
В языке С++ нет необходимости явно использовать ключевое слово ег гос1 при объявлении переменной данного типа. Так, для структуры зсгосЬ Иус1азе объекты данных можно описывать следующим образом: Иус1аее Л, Э, с; Обьявлеьтие методов — это оп редел е ьь тле функций или процедур, которые могут вызываться как операции данного класса. Можью задавать полное определение или просто заголовок сигнатуры функции, в котором определяются все ее параметры, Этот второй пюсоб похож на определение пакета в языке Ада, где детали реализации функции моьут быть определены в любом месте в теле пакета. Такая заголо- П.З.
С++ 595 ночная информация необходима для генерации кода вызова функции вне определения класса. Каждый член класса имеет атрибут доступа, который описывает видимость этого члена. Для каждого компонента класса можно задать один из трех возможных атрибутов доступа. Атрибут роЫ 1с (открытый) обозначает, что данное имя известно за пределами класса. Атрибут ргоЬес1еЬ (защишенный) подразумевает, что данное имя может использоваться только в производных классах.
Третий атрибут ргд чаге (закрытый) указывает, что данное имя может использоваться только внутри класса, содержащего его объявление. Атрибут доступа предшествует наименованию компонента класса, как в следующем компоненте ргодесгеп: чоШ дедча1иеыпд +а, (пд Ы ( *а - Ь; ) который присваивает, используя передачу параметра по ссылке, х.-значение параметра Ь объекту, переданному как 1-значение указателя а.
Однажды заданный, атрибут доступа остается атрибутом по умолчанию, пока не будет изменен. Если атрибут доступа не указан, по умолчанию используется атрибут рш чаЬе. Дружественные классы. Атрибуты доступа ргоЬесЬе0 и рг1ча1е иногда создают больше ограничений, чем необходимо. Иногда некоторьш класс может позволить другому классу получить доступ к своим закрытым данным. Эта возможность осуществляется объявлением одного класса дружественным (Сг1 еп0) по отношению к другому, которому в результате будут доступны внутреннис структуры первого. Например, в листинге П.5 класс ОаЬа5Ьоге определен как производный класс от класса ОасаСопчегЬ для того, чтобы иметь доступ к защищенному (ргоЬесЬео) методу сопчегг.
Вместо мого класс ОаЬаБЬоге можно было бы сделать базовым, а внутри класса ОаЬаСопчегЬ определить его как дружественный: с1а55 ОддаСопчегд (ргогесгеоп дп1 сопчегмспаг сЫ (гедпгп СП-'0':! Ггдепа с1аад ОдгаЗСсге; ]: В этом случае функция ОатаСопчегЫ сопчегг будет видна внутри класса Оага51оге. Область видимости компонента класса — это имя того класса, в котором он определен. Например, в объявлении с1д55 певс1д55 (ргодесдеа, чсю дедча!ие(шг *а, 1ПС Ы ( "а = Ь; !. роЫас: дпд х; 1 каждый компонент можно было бы онрелслчн ь как пенс!ада.: детча(ое и печдс1а55:: х. Прн объявлении метода тело метода можно определять вне определения класса, например: с1555 певс1д55 ( ргодесдеп' чп ', ' ' ча1 па( 1ПС 'а .
1 пг Ы : рчЫ дс: дпг х. 1 пехс1а55::дегчд1чем ПС *а. 1ПС Ы ( *а = Ь: !. Размещение классов. Объекты данных определенного пользователем класса объявляются так же, как и другие объекты данных; например, объект класса пдхчс! а55, описанного выше, можно объявить следующим образом: пенс!555 Н 596 Приложение. Обзоры языков Ссылки на компоненты этого объекта задаются так же, как и на компоненты структуры збгис1, например объект данных и, х, метод Ь), зебуа1не.
Указатели ЬЬ1з. В экземплярах класса пеьтс1азз, описанного выше, таких как пеис1аяя 1, 3 вызов зебуа! Ое для объекта т будет определяться как 1. зебуа)не(йп, и) и будет транслироваться так же, как если бы было записано пеыс1азз::зебуз1нейт, бв, и). То есть, чтобы различать разные экземпляры класса пеыс1азз, вызывается единственная копия метода зебуа1не с указателем на фактический объект данных т.
Аналогично вызов О.зебнз1ОЕ инициирует выЗОв пЕЬС1азз::зебуа1оеЯ),йп,п). Значение этого первого указателя на фактический параметр данных называется указателем сЬ ! з и его можно использовать внутри объявлений методов. Например, если определение класса выглядит следующим образом: с1юя вус1аяд ( ве ГЬ об ьч рю чые: Вус1аьь "ОЬЗесм ) то компонент ОЬтесб будет указателем на объект класса Нус1ззк Метод, который устанавливаетт значение указателя ОЬ) есб одного объекта класса Нус1а з з таким образом, чтобы он указывал на другой объект класса Нус1ззз, можно задать слелуюшим образом: вус1д55 т, // Обьявляются два обьента т яетро1пгег().детротптег()); // Уназятепь обьеита ) передается обьеиту 1 где дебро! пбег н деброт пбег определяются следуюшим образом: вус1азь.:детротпгег() !гебогп ХЬ(гн) вус1аья;:ьетротпсег(я(ус!аья *х) (Оь!есс - х;) Иттициализация.
Если имя метода, указанное в его объявлении, совпадает с именем класса, этот метод называется кот/стпрукто)том класса и вызывается всякий раз, когда в памяти размещается объект данного класса. Нри объявлении конструкторов они не должны возвращать значение или иметь возвращаемый тип. Аналогично метод с названием -иия ипассз называется десптруктором и вызывается всякий раз, когда происходит освобождение памяти, занимаемой экземпляром класса. Например, следующий код: с!ась гат1опа! ( рнЫ!с гагтопа1(тпт гв 1пт Ы (пивегагог - а. Оеповтпагог - Ь, ) -саттона!() (пнвегатог " О; беповшабог - О: ) // разруюение //янанения ргтуасе: тпт повегатог: тпс Оеповтпасог; ) вдтп() (гастона! яенуа!ие(1.2):) размещает Неь/Ча1не как объект типа габт опа1 с компонентами 1 и 2.
Добавляя объявление гытопд1() (пнвегдгог - 1: бепояппатог - 1;) в определение нашего класса, мы тем самым реализуем инициализацию объектов класса гзб1опз! по умолчанию, так что отпадает необхолимость присваивать им исхолные значения габтопа1 и, у. г п.З. С++ 597 Производные классы. Информацию можно передавать из одного класса в другой, используя обозначение производного класса: с1ам производный класс: базовый класс (конпонент класса,: конпонент класса,; конпонент класса„: ] где производный класс — имя определяемого нового класса, а базовый класс — это ба- зовый класс, используемый для создания производного класса. Все открытые и за- щищенные компоненты базового класса становятся соответственно открытыми и защищенными компонентами в производном классе, за исключением тех имен, которые переопределяются в производном классе.
Для всех компонентов базового класса можно по умолчанию задать способ до- ступа, как в следующем примере: с1ам производный класс:атрибут доступа базовый нласс ( ] где атрибут доступа может задаваться либо риЫ т с, либо ргосесгеб, либо рг(часе. Виртуальные функции. В большинстве случаев связь метода и исходной про- граммы, которую нужно вьшолнить, определяется статически во время трансля- ции, Однако это связывание можно отложить до момента выполнения программы, если использовать виртуизтьные функции.