Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:

Ответы_ТП

.pdf
Скачиваний:
9
Добавлен:
21.05.2015
Размер:
880.4 Кб
Скачать

Поскольку в этом примере класс в наследуется классом D и члены i и j объявлены защищенными в классе В (т.е. с использованием модификатора доступа protected), метод setk() может получить к ним доступ. Если бы члены i и j были объявлены в классе в закрытыми, класс D не имел бы к ним права доступа, и программа не скомпилировалась бы.

Подобно модификаторам public и private модификатор protected остается со своим членом независимо от реализуемого количества уровней наследования. Следовательно, при использовании производного класса в качестве базового для создания другого производного класса любой защищенный член исходного базового класса, который наследуется первым производным классом, также наследуется в статусе защищенного и вторым производным классом.

8. Индексаторы

Индексация массивов реализуется с использованием оператора " [ ]". В своих классах можно перегрузить его, но не прибегая к "услугам" метода operator(), а посредством создания индексатора(indexer). Индексатор позволяет обеспечить индексированный досту п к объекту. Главное назначение индексаторов —поддержать создание специализированных массивов, на которые налагается одно или несколько ограничений. При этом индексаторы можно использовать в синтаксисе, подобном реализованному в массивах. Индексаторы могут характеризоваться одной или несколькими размерностями.

Одномерный индексатор имеет следующий формат.

тип_элемента this[int индекс] {

// Аксессор считывания данных,

get {

// Возврат значения, заданного элементом индекс.

}

// Аксессор установки данных,

set {

//Установка значения, заданного

//элементом индекс.

}}

Здесь тип_элемента — базовый тип индексатора. Таким

образом, тип_элемента — это тип каждого элемента, к которому предоставляется доступ посредством индексатора. Он соответствует базовому типу массива. Параметр индекс получает индекс опрашиваемого (или устанавливаемого) элемента. Строго говоря, этот параметр не обязательно должен иметь тип int, но поскольку индексаторы обычно используются для обеспечения индексации массивов, целочисленный тип —наиболее подходящий.

В теле индексатора определяются два аксессора (средства доступа) с именами get иset. Аксессорподобен методу за исключением того, что в нем отсутствует объявлениетипа возвращаемого значения и параметров. При использовании индексатора аксессоры вызываются автоматически, и в качестве параметра оба аксессора принимают индекс. Если индексатор стоит слева от оператора присваивания, вызывается аксессорset и устанавливается элемент, заданный параметром индекс. В противном случае вызывается аксессорget и возвращается значение, соответствующее параметру индек c. Метод set также получает значение (именуемое value), которое присваивается элементу массива, найденному по заданному индексу.

Одно из достоинств индексатора состоит в том, что он позволяет точно управлять характером доступа к массиву, "отбраковывая" попытки некорректного доступа. Рассмотрим пример. В следующей программе класс FailSoftArray реализует массив, который "вылавливает" ошибки нарушения границ, предот вращая возникновение исключительных ситуаций. Это достигается за счет инкапсуляции массива как закрытого члена класса и осуществления доступа к этому массиву только через индексатор.

//Использование индексатора для создания

//отказоустойчивого массива.

using System;

classFailSoftArray {

int[] a; // Ссылканамассив.

publicint Length; // Length - открытыйчлен.

publicboolerrflag; // Индикаторрезультата

//последней операции.

//Создаем массив заданного размера,

publicFailSoftArray(int size) {

a = new int[size];Length = size;}

//Это - индексатор для класса FailSoftArray. publicint this[int index] {

//Это - get-аксессор.

get {if(ok(index)) {errflag = false;return a[index];} else {errflag = true;return 0;}

}

// Это - set-аксессор.

set {if(ok(index)) {a[inde x] = value;errflag = false;} elseerrflag = true;}

}

//Методвозвращаетзначение true, если

//индекс - в пределах границ,

privatebool ok(int index) {

if(index >= 0 & index < Length) return true; returnfalse;

}

}

// Демонстрируемотказоустойчивыймассив , classFSDemo {

public static void Main() { FailSoftArrayfs = new FailSoftArray(5); int x;

Console.WriteLine("Мягкоеприземление. ") ; for(inti=0; i< (fs.Length * 2) ;i++)fs[i] = i*10; for(inti=0; i< (fs.Length * 2);i++)

{x = fs[i];if(x != -1) Console.Write(x + " ") ;} Console.WriteLine();

// Теперь генерируем некорректный доступ.

Console.WriteLine("\nРабота с уведомлением об ошибках."); for(inti=0; i< (fs.Length * 2); i++) {

fs[i] * i*10;if(fs.errflag)

Console.WriteLine("fs[" + i + "] внеграниц");

}

for(inti=0; i< (fs.Length * 2);i++){

x = fs[i] ;if(!fs.errflag) Console.Write(x + " " ) ; elseConsole.WriteLine("fs[" + i + "] внеграниц");

}

}

}

При выполнении этой программы получаем такие результаты:

"Мягкое приземление".

0 10 20 30 40 0 0000

Работа с уведомлением об ошибках.

fs[5] вне границ

fs[6] вне границ

fs[7] вне границ

fs[8] вне границ

fs[9] вне границ

0 10 20 30 40 fs[5] вне границ

fs[6] вне границ

fs[7] вне границ

fs[8] вне границ

fs[9] вне границ

Аксессорget предотвращает ошибки нарушения границ. Если заданный индекс находится в пределах границ, аксессорget возвращает элемент, соответствующий этому индексу. А если переданный индекс выходит за пределы границ, операции с массивом не выполняются, но и ничего страшного при этом не происходит. В данной версии класса FailSoftArray переменная errflag содержит результат выполнения каждой операции. Чтобы узнать, как завершилась очередная операция, достаточно проанализировать это поле.

Аксессорset () предотвращает ошибк и нарушения границ. Если заданный индекс находится в пределах границ, значение, переданное через переменную value, присваивается соответствующему элементу массива. В противном случае признак ошибки errflagустанавливается равным значениюtrue.

Индексаторы необязательно создавать с поддержкой как get-, так и set-аксессоров. Можно создать индексатор, предназначенный только для чтения, реализовав лишь get-аксессор. И точно также можно создать индексатор, предназначенный только для записи, реализовав лишь set-аксессор.

Индексаторы можно перегружать. Чаще всего индексатор перегружается, чтобы иметь возможность использовать объект класса в качестве индекса, значение которого вычисляется специальным образом.

Индексатор может не использовать базовый массив. Вполне достаточно, чтобы индексатор обеспечивал функционирование, которое для пользователя выглядело бы, как то, что обеспечивают массивы.

На использование индексаторов накладывается два ограничения. Во-первых, поскольку в индексаторе не определяется область памяти, получаемое индексатором значение нельзя передавать методу в качестве ref- или out-параметра. Во-вторых, индексатор должен быть членом экземпляра своего класса, поэтому его нельзя объявлять с использованием ключевого слова static.

Можно создавать индексаторы и для многомерных массивов.

9. Инициализация пересечений. Задание базового типа перечисления

Одно или несколько символов в перечислении можно определить с помощью инициализатора. Это реализуется путем исп ользования знака "равно" и последующего целого значения. Символам, стоящим после инициализатора, присваиваются значения, превышающие предыдущее значение инициализации. Например, следующий фрагмент кода присваивает число 10 символу RedDel. enum apple {Jonathan,

GoldenDel, RedDel = 10, Winsap, Cortland, Mclntosh };

Вот какие значения имеют теперь эти символы:

Jonathan 0

GoldenDel 1

RedDel 10

Winsap 11

Cortland 12

Mclntosh 13

6.9.2 Задание базового типа перечисления

По умолчанию перечисления используют типint, но можно также создать перечисление любого другого целочисленного типа, за исключением типа char. Чтобы задать тип, отличный от int, укажите этот базовый тип после имени перечисления и двоеточия. Например, следующая инструкция создает пе речисление apple с базовым типом byte.

enum apple : byte {Jonathan, GoldenDel, RedDel, Winsap, Cortland, Mclntosh};

Теперь член apple.Winsap, например, представляет собой byte-

значение.

10. Интерфейсные свойства и индексаторы

Как и методы, свойства определяются в интерфейсе без тела. Ниже приведен формат спецификации свойства.

// Интерфейсное свойство

тип имя{

get;

set;

}

Свойства, предназначенные только для чтения или только для записи, содержат только get- или set-элемент, соответственно.

6.4 Интерфейсные индексаторы

В интерфейсе можно определить и индексатор. Объявление индексатора в интерфейсе имеет следующий формат записи:

// Интерфейсный индексатор

тип_элемента this[int индекс]{

get;

set;

}

Индексаторы, предназначенные только для чтения или то лько для записи, содержат только get - или set -метод, соответственно.

11. Использование Try и Catch

Ядром обработки исключений являются блоки try и catch. Эти ключевые слова работают "в одной связке"; нельзя использовать слово try без catch или catch без try. Вот каков формат записи try/catch-блоков обработки исключений:

try {

// Блок кода, подлежащий проверке на наличие ошибок.

}

catch {ExcepType1exOb) {

// Обработчик для исключения типа ExcepType1.

}

catch (ExcepType2 exOb) {

// Обработчик для исключени я типа ЕхсерТуре2.

}…

Здесь ЕхсерТуре — это тип сгенерированного исключения.

После " выброса" исключение перехватывается соответствующей инструкцией catch, которая его обрабатывает. Из формата записи try/catch-блоковвидно, с try-блоком может быть связана не одна, а несколько catch-инструкций. Какая именно из них будет выполнена, определит тип исключения. Другими словами, будет выполнена та catch - инструкция, тип исключения которой совпадает с типом сгенерированного исключения (а все оста льные будут проигнорированы). После перехвата исключения параметр ехОbпримет его значение.

Известно, что попытка индексировать массив за пределами его границ вызывает ошибку нарушения диапазона. В этом случае С#- система динамического управления генерирует и сключение типа IndexOutOfRangeException , которое представляет собой стандартное исключение, определенное языком С#.

using System; // Демонстрация обработки исключений,

class ExcDemo1 {

public static void Main() {

int[] nums = new int [4];

try {

Console.WriteLine(

"Перед генерированием исключения.");

// Генерируем исключение, связанное с попаданием

// индексавнедиапазона,

for(int i=0; i < 10; i++) {

nums[i] = i;

Console.WriteLine("nums[{0}]: {1}", i, nums[i]);

}

Console.WriteLine("Этот текст не отображается. ");

}

catch (IndexOutOfRangeException) {

// Перехватываем исключение.

Console.WriteLine("Индекс вне диапазона!");

}

Console.WriteLine("После catch -инструкции.");

}}

При выполнении этой программы получаем такие результаты:

Перед генерированием исключения.

nums[0]: 0

nums[1]: 1

nums[2]: 2

nums[3]: 3

Индекс вне диапазона!

После catch -инструкции.

Тип исключения должен совпадать с типом, заданным в catchинструкции. В противном случае это исключение не будет перехвачено. Одно из основных достоинств обработки ис ключений состоит в том, что она позволяет программе отреагировать на ошибку и продолжить выполнение. После обработки исключение удаляется из системы.

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]