Глава 12: О классах подробнее



 

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

 

Функции‑"друзья"

 

В C++ существует возможность разрешить доступ к закрытым членам класса функциям, которые не являются членами этого класса. Для этого достаточно объявить эти функции "дружественными" (или "друзьями" ) по отношению к рассматриваемому классу. Чтобы сделать функцию "другом" класса, включите ее прототип в public ‑раздел объявления класса и предварите его ключевым словом friend . Например, в этом фрагменте кода функция frnd() объявляется "другом" класса cl .

 

 

Ключевое слово friend предоставляет функции, которая не является членом класса, доступ к его закрытым членам.

Как видите, ключевое слово friend предваряет остальную часть прототипа функции. Функция может быть "другом" нескольких классов.

Рассмотрим короткий пример, в котором функция‑"друг" используется для доступа к закрытым членам класса myclass .

 

 

В этом примере функция sum() не является членом класса myclass . Тем не менее она имеет полный доступ к private ‑членам класса myclass . В частности, она может непосредственно использовать значения х.а и х.b . Обратите также внимание на то, что функция sum() вызывается обычным образом, т.е. без привязки к объекту (и без использования оператора "точка" ). Поскольку она не функция‑член, то при вызове ее не нужно квалифицировать с указанием имени объекта. (Точнее, при ее вызове нельзя задавать имя объекта.) Обычно функции‑"другу" в качестве параметра передается один или несколько объектов класса, для которого она является "другом" , как в случае функции sum() .

Несмотря на то что в данном примере мы не извлекаем никакой пользы из объявления функции sum() "другом" , а не членом класса myclass , существуют определенные обстоятельства, при которых статус функции‑"друга" имеет большое значение. Во‑первых, функции‑"друзья" могут быть полезны для перегрузки операторов определенных типов. Во‑вторых, функции‑"друзья" упрощают создание некоторых функций ввода‑вывода. Об этом речь впереди.

Третья причина использования функций‑"друзей" состоит в том, что в некоторых случаях два (или больше) класса могут содержать члены, которые находятся во взаимной связи с другими частями программы. Например, у нас есть два различных класса, которые при возникновении определенных событий отображают на экране "всплывающие" сообщения. Другие части программы, которые предназначены для вывода данных на экран, должны знать, является ли "всплывающее" сообщение активным, чтобы случайно не перезаписать его. В каждом классе можно создать функцию‑член, возвращающую значение, по которому можно судить о том, активно сообщение или нет; однако проверка этого условия потребует дополнительных затрат (т.е. двух вызовов функций вместо одного). Если статус "всплывающего" сообщения необходимо проверять часто, эти дополнительные затраты могут оказаться попросту неприемлемыми. Однако с помощью функции, "дружественной" для обоих классов, можно напрямую проверять статус каждого объекта, вызывая только одну функцию, которая будет иметь доступ к обоим классам. В подобных ситуациях функция‑"друг" позволяет написать более эффективный код. Эта идея иллюстрируется на примере следующей программы.

 

 

При выполнении программа генерирует такие результаты.

 

 

Поскольку функция idle() является "другом" как для класса С1 , так и для класса С2 , она имеет доступ к закрытому члену status , определенному в обоих классах. Таким образом, состояние объекта каждого класса одновременно можно проверить всего одним обращением к функции idle() .

Опережающее объявление предназначено для объявления имени классового типа до определения самого класса.

Обратите внимание на то, что в этой программе используется опережающее объявление (также именуемое опережающей ссылкой ) для класса С2 . Его необходимость обусловлена тем, что объявление функции idle() в классе С1 использует ссылку на класс С2 до его объявления. Чтобы создать опережающее объявление для класса, достаточно использовать формат, представленный в этой программе.

"Друг" одного класса может быть членом другого класса. Перепишем предыдущую программу так, чтобы функция idle() стала членом класса С1 . Обратите внимание на использование оператора разрешения области видимости (или оператора разрешения контекста) при объявлении функции idle() в качестве "друга" класса С2 .

 

 

Поскольку функция idle() является членом класса C1 , она имеет прямой доступ к переменной status объектов типа С1 . Следовательно, в качестве параметра необходимо передавать функции idle() только объекты типа С2 .

 

Перегрузка конструкторов

 

Несмотря на выполнение конструкторами уникальных действий, они не сильно отличаются от функций других типов и также могут подвергаться перегрузке. Чтобы перегрузить конструктор класса, достаточно объявить его во всех нужных форматах и определить каждое действие, связанное с соответствующим форматом. Например, в следующей программе объявляется класс timer , который действует как вычитающий таймер. При создании объекта типа timer таймеру присваивается некоторое начальное значение времени. При вызове функции run() таймер выполняет счет в обратном порядке до нуля, а затем подает звуковой сигнал. В этом примере конструктор перегружается трижды, предоставляя тем самым возможность задавать время как в секундах (причем либо числом, либо строкой), так и в минутах и секундах (с помощью двух целочисленных значений). В этой программе используется стандартная библиотечная функция clock() , которая возвращает количество сигналов, принятых от системных часов с момента начала выполнения программы. Вот как выглядит прототип этой функции:

 

 

Тип clock_t представляет собой разновидность длинного целочисленного типа. Операция деления значения, возвращаемого функцией clock() , на значение CLOCKS_PER_SEC позволяет преобразовать результат в секунды. Как прототип для функции clock() , так и определение константы CLOCKS_PER_SEC принадлежат заголовку <ctime> .

 

 

При создании в функции main() объектов а , b и с класса timer им присваиваются начальные значения тремя различными способами, поддерживаемыми перегруженными функциями конструкторов. В каждом случае вызывается конструктор, который соответствует заданному списку параметров и потому надлежащим образом инициализирует "свой" объект.

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

 

Динамическая инициализация

 

В C++ как локальные, так и глобальные переменные можно инициализировать во время выполнения программы. Этот процесс иногда называют динамической инициализацией . До сих пор в большинстве инструкций инициализации, представленных в этой книге, использовались константы. Однако переменную можно также инициализировать во время выполнения программы, используя любое С++‑выражение, действительное на момент объявления этой переменной. Это означает, что переменную можно инициализировать с помощью других переменных и/или вызовов функций при условии, что в момент выполнения инструкции объявления общее выражение инициализации имеет действительное значение. Например, следующие варианты инициализации переменных абсолютно допустимы в C++,

 


Дата добавления: 2018-09-22; просмотров: 298; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!