Г. Шилдт - С# 3.0 Полное руководство. 2010 (1160798), страница 41
Текст из файла (страница 41)
оЬ.Зепй1рпа(-99)т оЬ.Яеевека(19)) Сопзо1е.нгьое11пе("оЬ.а1рпа равно " + оь.пеой1рпа())т Сопзо1е.нг1теъ1пе("оь.ьепз равно " + оь.зесвеса())т // Следующие виды доступа к членам з1рпа и Ьзпз // данного класса не разрешаются. О оЬ.а1рьа = 10т // Ошибка! з1рпа — закрытый член! // оь.ьеод = 9т // Ошибка! пека — закрытый член! // Член Чалхпа данного класса доступен // непосредственно, поскольку он является открытым. оь.чашша = 99) ) ) Как видите, в классе мус1азз член а1рьа указан явно как ргйчасе, член Ьеса становится ргтуасе по умолчанию, а член дашша указан как рпь11с. таким образом, члены а1рьа и Ьеьа недоступны непосредственно из кода за пределами данного КЛасса, Поскольку они являются закрытыми. В частности, ими нельзя пользоваться непосредственно в классе йссеззпешо.
Они доступны только с помощью таких открытых (риь11с) методов, как Зеьй1рьа () и Оеой1рьа () . Так, если удалить символы комментария в начале следующей строки кода: О оЬ.а1рпа 10; // Ошибка! а1рпа — закрытый член! то приведенная выше программа не будет скомпилирована из-за нарушения правил доступа. Но, несмотря на то, что член а1рьа недоступен непосредственно за пределами класса МуС1азз, свободный доступ к нему организуется с помощью методов, определенных в классе мус1азз, как наглядно показывают методы Бесй1рьа () и бесй1рьа () .
Это же относится и к члену Ьеса. Из всего изложенного выше можно сделать следующий важный вывод: закрытый член может свободно использоваться другими членами этого же класса, но недоступен для кода за пределами своего класса. Организация закрытого и открытого доступа Правильная организация закрытого и открытого доступа — залог успеха в объектноориентированном программировании. И хотя для зтого не существует твердо установленных правил, ниже перечислен ряд общих принципов, которые могут служить в качестве руководства к действию.
204 Часть С Язык С№ ° Члены, используемые только в классе, должны быть закрытыми. ° Данные экземпляра, не выходящие за определенные пределы значений, должны быть закрытыми, а при организации доступа к ним с помощью открытых методов следует выполнять проверку диапазона представления чисел. ° Если изменение члена приводит к последствиям, распространяющимся за пределы области действия самого члена, т.е. оказывает влияние на другие аспекты объекта, то этот член должен быть закрытым, а доступ к нему — контролируемым.
° Члены, способные нанести вред объекту, если они используются неправильно, должны быть закрытыми. Доступ к этим членам следует организовать с помощью открытых методов, исключающих неправильное их использование. ° Методы, получаюшне и устанавливающие значения закрытых данных, должны быть открытыми. ° Переменные экземпляра допускается делать открытыми лишь в том случае, если нет никаких оснований для того, чтобы они были закрытыми. Разумеется, существует немало ситуаций, на которые приведенные выше принципы не распространяются, а в особых случаях один или несколько этих принципов могут вообще нарушаться. Но в целом,.следуя этим правилам, вы сможете создавать объекты, устойчивые к попыткам неправильного их использования.
Практический пример организации управления доступом Для чтобы стали понятнее особенности внутреннего механизма управления доступом, обратимся к конкретному примеру. Одним из самых характерных примеров объектноориентированного программирования служит класс, реализующий стлек — структуру данных, воплощающую магазинный список, действующий по принципу "последним пришел — первым обслужен".
Свое название он получил по аналогии со стопкой тарелок, стоящих на столе. Первая тарелка в стопке является в то же время последней использовавшейся тарелкой. Стек служит классическим примером объектно-ориентированного программирования потому, что он сочетает в себе средства хранения информации с методами доступа к ней. Для реализации такого сочетания отлично подходит класс, в котором члены, обеспечивающие хранение информации в стеке, должны быть закрытыми, а методы доступа к ним — открытыми. Благодаря инкапсуляции базовых средств хранения информации соблюдается определенный порядок доступа к отдельным элементам стека из кода, в котором он используется. Для стека определены две основные операции: помесятить данные в стек и извлечь их оттуда.
Первая операция помещает значение на вершину стека, а вторая — извлекает значение из вершины стека. Следовательно, операция извлечения является безвозвратной: как только значение извлекается из стека, оно удаляется и уже недоступно в стеке. В рассматриваемом здесь примере создается класс ясасх, реализующий функции стека. В качестве базовых средств для хранения данных в стеке служит закрытый массив. А операции размешения и извлечения данных из стека доступны с помощью открытых методов класса зсасх.
Таким образом, открытые методы действуют по упомянутому выше принципу "последним пришел — первым обслужен". Как следует из приведенного ниже кода, в классе зсасх сохраняются символы, но тот же самый механизм может быть использован и для хранения данных любого другого типа. Глава 8. ПодраГ)нее о методах и классах 205 // Класс для хранения символов в стеке. цз1пс Яузсещ) с1азз Ясасн ( // Эти члены класса являются закрытыми. сваг[] зоскт // массив, содержащий стек апс соз) // индекс вершины стека // Построить пустой класс Яоасн для реализации // стека заданного размера.
рцЫас Яоаск(апо заве) ( воск = пен спас(вахе]т // распределить память для стека сов = От ) // Поместить символы в стек. рцЫас чохе Рцзо(спас сЫ 1Е(коз==акса.аепЯСЫ Сопзо1е.нг1оеП1пе(" — Стек заполнен.") гесцхпх зоск[ооз] = сЬ) сов++к ) // Извлечь символ из стека. рцЫас сваг Рор() ( ак(коз==о) ( Сопзо1е.мг1оеЬ1пе(" — Стек пуст.") геоагп (сваг) О; ) соз —; геоцгп всех[коз]т ) // Возвратить значение Сгие, если стек заполнен. рцЫас Ьоо1 1зуц11() ( гесцгп Сов==воск.Вепдоп( // Возвратить значение Сгце, если стек пуст.
рцЫас Ьоо1 1зЕщроу() ( кеоцгп Сов==от // Возвратить общую емкость стека. риЫас апо Сарас1оу() ( гевигп воск.Вендов) ) // Возвратить количество объектов, находящихся в // данный момент в стеке. 206 часть (. йзык 5» .риЬ11с 1пс песком() ( гегигп гов) ) Рассмотрим класс 5сас)к более подробно.
В начале этого класса объявляются две следующие переменные экземпляра: // Эти члены класса являются закрытыми. сйаг() ягсты // массив, содержащий стек 1пг говк // индекс вершины стека Массив вгс)к предоставляет базовые средства для хранения данных в стеке (в данном случае — символов). Обратите внимание иа то, что память для этого массива ие распределяется.
Это делается в конструкторе класса 5саск. А член сов этого класса содержит индекс вершины стека. Оба члена, сов и в сок, являются закрытыми, и благодаря этому соблюдается принцип "последним пришел — первым обслужен". Если же разрешить открытый доступ к члену вгс)к, то элементы стека окажутся доступными ие по порядку. Кроме того, член сов содержит индекс вершины стека, где находится первый обслуживаемый в стеке элемент, и поэтому манипулирование членом Сов в коде, находящемся за пределами класса 5йас)к, следует исключить, чтобы ие допустить разрушение самого стека. Но в то же время члены все]г и сов доступны пользователю класса 5 сас)к косвенным образом с помощью различиых отрытых методов, описываемых ниже. Рассмотрим далее конструктор класса 5сасх. // Построить пустой клаас 5саск для реализации // стека заданного размера. рий11с зсасн(1пс в»ге) вссх = пеи сйаг(вьве]; // распределить память для стека гов = О; Этому конструктору передается требуемый размер стека Ои распределяет память для базового массива и устанавливает зиачеиие переменной сов в нуль.
Следовательно, нулевое значение переменной сов указывает иа то, что стек пуст. Открытый метод Роя й () помеШает конкретный элемеит в стек, как показано ниже. // Поместить символы в стек. риЬ11с тоти Ривй(сйяг сй) ( 11(сов==вссв.вепдсы ( Сопво1е.вг1сеъ1пе(" — Стек заполнен."); гесигп( ) вгск(гов] = сйк говь+; ) Элемент, помещаемый в стек, передается данному методу в качестве параметра сй. Перед тем как поместить элемент в стек, производится проверка иа наличие свободного места в базовом массиве, а именно: ие превышает ли значение переменной сов длину массива всс)к.