Г. Шилтд - Самоучитель C++ (DJVU) (1114955), страница 59
Текст из файла (страница 59)
= и," :пс деЕ1() ( тесигп гр ) ю уу оггределение гкус1авв::1. переменная 1 по †прежне остается закрытым членом класса гпус1аяя гг. гпус1авв::1; 1пс глаъп() тус1аяя о1, о2; о1.векъ(10)р сопя « "о1.1: " « о1.сет1 О « '~п'; уу выводит значение 10 сопс « "о2.1: " « о2.0есг() « '~п'; уу также выводит 10 гегпгп 0; После выполнения программы на экране появится следуюшее: о1. и 10 о2П: 10 Глядя на программу, можно заметить, что фактически только для объекта о1 устанавливается значение статической переменной-члена 1.
Однако поскольку переменная 1 совместно используется объектами о1 и о2 (и, на самом деле, всеми объектами типа гпус1ааз), оба вызова функции яе11() дают один и тот же результат. Самоучитель С++ Обратите внимание, что переменная 1 объявляется внутри класса (пус1азв, но определяется вне его. Этот второй шаг гарантирует, что для переменной 1 будет выделена память. С технической точки зрения, определение класса является всего лишь определением типа и не более.
Память для статической переменной при этом не выделяется. Поэтому для вьщеления памяти статической переменной-члену требуется ее явное определение, 2. Поскольку статическая переменная — член класса существует еще до создания объекта этого класса, доступ к ней в программе может быть реализован без всякого объекта. Например, в следующем варианте предыдущей программы для статической переменной )устанавливается значение 100 без всякой ссылки на конкретный объект.
Обратите внимание на использование оператора расширения области видимости для доступа к переменной Е // Для обращения к статической переменной объект не нужен гбпс!иг(е <1овегеал~> пв(пд пагпеврасе вЫ; с1авв гнус!авв рпЫ)с: в1аг)с (п1 уоЫ вел~. (1пс и) ( 1 = и; ) 1п1 яе111) ( ге1пгп 1; ) )т тпп гаус1ааа::1; тпс татп () ( ыус1авв а1, о2; непосредственное задание значения переменной ГаУС1аае::1 = 100; У/ объекты не упоминаются сонг « "о1.1: " « о1.цест() « '~п'1 уу выводит 100 сопС « "о2, 1: " « о2.де11 (1 « ' ~п ' 1 у/ также выводит 100 ге1игп О; Так как статической переменной 1 присвоено значение 100, программа выво- дит на экран следующее: оц: 1ОО о2.1: 100 3.
Традиционным использованием статических переменных класса является координация доступа к разделяемым ресурсам, таким как дисковая память, принтер или сетевой сервер. Как вы уже, вероятно, знаете из своего опыта, координация доступа к разделяемым ресурсам требует некоторых знаний о 399 Глава !3. Пространства имен и другие темы последовательности событий. Чтобы понять, как с помощью статических переменных-членов можно управлять доступом к разделяемым ресурсам, изучите следующую программу. В ней создается класс ои[рв1, который поддерживает общий выходной буфер онйиГ, являющийся статическим символьным массивом.
Этот буфер используется для получения выходной информации, передаваемой функцией-членом ои1Ьа[О. Эта функция посимвольно передает содержимое строки згг. Сначала функция запрашивает доступ к буферу, а затем передает в него все символы згг. Функция предотвращает доступ в буфер другим объектам до окончания вывода. Понять работу программы можно по комментариям к ней. // Пример разделения ресурсов гппс!ибе (ьовггеат> ()ьпс1ибе <свгг!п0> ив!па пагпеврасе агбг с1ава он(рнГ ( агат!с с)тат оисЬий[255] г // это разделяемые ресурсы згаг!с 1пс ьпвае; // если переменная !пиве равна О, // буфер доступен; иначе — нет втаг!с 1пг офпбех; // индекс буфера с)заг а1г[ЯО] ! !и! 1; // индекс следующего символа строки !и! в)зо; // идентификатор объекта должен быть положительным рцЬ11с: сссрнг (1пс ~ч, с)заг жв) астору(агг, в); ! = О; иван> = и; /* Ота функция возвражает -1 при ожидании буфера; Π— при завершении вывода; ибо — если буфер все еце используется.
* / тт1в риеЬцй () ( Ы(!ест[1]! ( // вывод завершен тпцве = О," // освобождение буфера гегцгп О; // признак завершения ) 1т (! 1пвае) тпцве =. ыЬо; // захва буфера 11(1ппве ! — 'йо) гегцгп -1; // буфер кто-то использует ьг(асг[ь]) ( // символы еще остались оигЬШ[охпбех] =- агг[1]) 1++) о1пбех++; оц1Ьи1[оапбех] = ' 10') // последнии всегда идет нуль гебцгп 1; гегцгп О; Самоучитель О~+ чоЫ вЬои() ( сопл « опсЬпГ « '~п';) с?зал оп~рис:."опсьпй(255]; // это разделяемые ресурсы пб обурил::1ппве = 0; // если переменная ?ппее равна О, буфер доступен; иначе — нет ?пс оисрпл::о!паек 0; // индекс буфера ?пс юа1п() оШри( о1(1, "Это проверка "), о2 (2, "статических переменнык") иЬ(1е (о1.рп?Ьп?() 1 о2.рп?Ьит() ); // вывод символов о1. зйоы (); гейл-и 0; 4.
Статические функции-члены применяются достаточно редко, но для предварительной (до создания реального объекта) инициализации закрытых статических данных-членов они могут оказаться очень удобными. Например, ниже представлена совершенно правильная программа. (?1пс1пе?е <1озлгеащ> пк(па пагпезрасе зс<(? с1аев зса~1с аппо беппо ( агат(с )пт риЬ11с: зтат(с уоЫ !пав.е(1пс х) ( 1 = х? уоЫ ейои() ( сопт « 1; ) ?пс аеас!с аппо бе?ко::1? // определение переменной 1 ?пс па1п1) // инипиализапия статических данных еще до создания объекта злас1с кппс оекю::1п1С(100)? влал1с липс с?е?ао х; х.зЬои(); // вывод на экран значения 100 лесп сп 0; Здесь вызов функции !и!!О инициализирует переменную 1 еп(е до создания объекта типа з(а(1с Йпс йепю.
40 1 Глава 13. Пространства имен ид гие темы 1. Переделайте пример 3 так, чтобы на экране отображался тот объект, который осугцествляет вывод символов, и тот объект или те объекты, для которых изза занятости буфера вывод запрещен. 2. Одним из интересных применений статических переменных-членов является хранение информации о количестве объектов класса, существующих в каждый конкретный момент времени. Для этого необходимо увеличивать на единицу статическую переменную-член каждый раз, когда вызывается конструктор класса, и уменьшать на единицу, когда вызывается деструктор. Реализуйте эту схему и продемонстрируйте ее работу.
13.4. Постоянные и модифицируемые члены класса Функции — члены класса могут объявляться постоянными (с идентификатором сопяГ). Если функция объявлена постоянной, она не может изменить вызывающий ее объект. Кроме этого, постоянный объект не может вызвать непостоянную функцию-член. Тем не менее, постоянная функция-член может вызываться как постоянными, так и непостоянными объектами. Для задания постоянной функции-члена используйте ее форму, представленную в следующем примере: с1авн Х ( гнс вове чанг рцЬ11.с: ° 1нс 11(1 сосне; // постоянная функция-член Обратите внимание, что ключевое слово сопМ указывают следом за списком параметров функции, а не перед именем функции.
Возможна ситуация, когда вам понадобится, чтобы функция-член, оставаясь постоянной, тем не менее была способна изменить один или несколько членов класса. Это достигается заданием модифицируемых членов класса (ключевое слово пшГаЫе), Модифицируемый член класса можно изменить с помощью постоянной функции-члена. 1. Функция-член объявляется постоянной, чтобы предотвратить возможность изменения вызвавшего ее объекта. Для примера рассмотрим следующую программу. Самоучитель /* Пример объявления постоянных функций-членов. Данная программа содержит ошибку и коьлтилироваться не Судет */ ()1пс1пс)е <1оякгеат> пяупд патеярасе ассар с1аяя Вето ( 1пв 1; рц)з11с: фпс дес1 () сопел гепигп 1; 1! здесь все правильно уоЫ яев1(1п~ х) сопел ( = х; !! Ошибка! ! ! )' 1пс патп ( ) Вето оЬ; оЬ.весь(1900)," сопя « о)о.дес1(): гевпгп 0; Данная программа не будет компилироваться„поскольку функция-член яе((() объявлена постоянной, что означает невозможность изменения вызывающего ее объекта.
Таким образом, попытка изменения функцией переменной ( ведет к ошибке. С другой стороны, поскольку функция йе0() не меняет переменной (, она совершенно правильна. 2. Чтобы допустить изменение избранных членов класса постоянной функцией- членом, они задаются модифицируемыми. Ниже представлен пример. Пример задания модифицируемого члена класса ()1пс1ибе <говлгеатп> пнувши патеярасе ябб; с1аяя Вето тиса)з1е 1пп 1пг0 рц)з11с: 1пс декф() сопел ( гегпгп 1; О здесь все правильно уоЫ век1(1пп х) сопел ( = х; !! теперь все правильно Глава 13. Пространства имен и другие темы 403 /* Если убрать комментарии вокруг этой срункции, то программа компилироваться не Судет хоЫ вет1((пт х) сопят ( = х; // здесь прежняя ошибка ш( ша(п () Ревю оЬ; оЬ.
веИ (1900); соцт «оЬ.дет1(); гетцгп Ор Здесь переменная 1 задана модифицируемой, поэтому ее может изменить функция-член зе(10. Тем не менее, поскольку переменная ( по-прежнему остается не модифицируемой, постоянная функция-член зе60 не может изменить ее значение. !. В следуюшей программе сделана попытка создать простой таймер для измерения временных интервалов. По истечении каждого такого интервала тай- . мер должен подавать звуковой сигнал.
К сожалению, в том виде, в котором программа представлена, она компилироваться не будет. Найдите и исправьте ошибку. // В этой программе имеется ошибка Ипс1ибе <1овсгеагп> ив(пя патпеврасе вас(у с!ава Соопсоонп ( (пт ьпсгз (пт тагнет; (пт сиггепт; рцЬ11с: Соцпсвоип(ьпс с1е1ау, (п( 1 — 1) тагяст = с(е1ау; (пег = сцггспт = О; Ьоо1 соцп 1пч ( ) сопят ( сцггепт +-= (пег; 404 Самоучитель С++ Ы(спххепх >= (агапе() ( сов( « "~а"; хесихп йа1яе; сопя « спххепс «" хеспхп схпе; 1п' па1п() ( Саппхоаип сЬ(1ОО 2) иЬ11е(пЬ.соппх1пд()); хехпхп О; 2.
Может ли постоянная функция-член вызвать непостоянную функцию? Если нет, то почему? 13.5. Заключительный обзор конструкторов Хотя тема конструкторов в этой книге уже обсуждалась, некоторые аспекты их применения остались нераскрытыми. Рассмотрим следующую программу: ()ьпс1ибе <аовххеап~> ив(пд патеярасе вех(р с1аяв п1ус1аяв 1пс а; рпЬ11с: хаус1аяа(1пс х) ( а = х; гпс дева() ( хехихп а; тпх пеьп() ( тус1аяв оЬ(4) сопя « сЬ.деха() хехпхп О; Глава 13.