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

Ответы_ТП

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

1.Виртуальные методы и их предопределение

Виртуальным называется метод, объявляемый с помощью ключевого слова virtual в базовом классе и переопределяемый в одном или нескольких производных классах. Таким образом, каждый производный класс может иметь собственную версию виртуального метода. Виртуальные методы представляют интерес с такой позиции: что произойдет, если виртуальный метод будет вызван посредством ссылки на базовый класс. Какую именно версию метода нужно вызвать, С# определяет по типу объекта, на который указываетэта ссылка, причем решение принимается динамически, во времявыполнения программы . Следовательно, если имеются ссылки на различныеобъекты, будут выполняться различныеверсии виртуального метода. Другими словами, именно тип объекта, на который указывает ссылка (а не тип ссылки) определяет, какая версия виртуального метода будет выполнена. Таким образом, если базовый класс содержит виртуальный метод и из этого класса выведены производные классы, то при наличии ссылки на различные типы объектов (посредством ссылки на базовый класс) будут выполняться различные версии этого виртуального метода.

Чтобы объявить ме тод в базовом классе виртуальным, его объявление необходимо предварить ключевым словом virtual . При переопределении виртуального метода в производном классе используется модификатор override. Итак, процесс переопределения виртуального метода в производном классе иногда называется замещениемметода (methodoverriding ). При переопределении метода сигнатуры типа у виртуального и метода -заменителя должны совпадать. Кроме того, виртуальный метод нельзя определять как статический (с использованием слова static) или абстрактный (с использованием слова abstract ).

Переопределение виртуального метода формирует базу для одной из самых мощных концепций С#: динамической диспетчеризации методов. Динамическая диспетчеризация методов — это механизм вызова переопределенного ме тода во время выполнения программы, а не в период компиляции. Именно благодаря механизму диспетчеризации методов в С# реализуется динамический полиморфизм.

// Демонстрация виртуального метода. usingSystem;

classBase {

// Создаем виртуальный метод в базово м классе, public virtual void who () {

Console.WriteLine(" Метод who() вклассе Base.");

}}

classDerived1 :Base {

// Переопределяем метод who() в производном классе, public override void who() {

Console.WriteLine(" Метод who() вклассе Derived1")

}}

classDerived2 :Base {

//Сновапереопределяемметод who()

//в другом производном классе,

publicoverridevoidwho() {

Console.WriteLine(" Метод who() вклассе Derived2

}}

class OverrideDemo { public static void Main() { Base baseOb = new Base();

Derived1dOb1 = ne wDerived1()

Derived2 dOb2 = new Derived2()

Base baseRef; // Ссылканабазовыйкласс .

baseRef = baseOb;

baseRef.who();

baseRef = dOb1;

baseRef.who() ;

baseRef = dOb2;

baseRef.who() ;

}}

Вот результаты выполнения этой программы:

Метод who() в классе Base.

Метод who() в классе Derived1

Метод who() в классе Derived2

В программе создается базовый класс Base и два производных класса — Derived1 и Derived2. В классе Base объявляется метод с именем who(), а производные классы его переопределяют. В методе Main() объявляются объекты типа Base, Derived1 и Derived2, а также ссылка baseRef типа Base. Затем программа поочередно присваивает ссылку на объект каждого типа ссылке baseRef и использует эту ссылку для вызова метода who(). Как показывают результаты выполнения э той программы, нужная для выполнения версия определяется типом объекта, адресуемого в момент вызова, а не " классовым" типом ссылки baseRef.

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

Свойства также можно модифицировать с помощью ключевого слова virtual, а затем переопределять с помощью ключевого слова override.

2.Выполнение операций над значениями встроенных С# типов

Вы видели, как перегрузить оператор "+", чтобы он суммировал координаты одного ThreeD-объекта с координатами другого. Однако это не единственный способ определения операции сложения для класса ThreeD. Например, может потребоваться суммирование какого -либо целого числа с каждой координатой ThreeD-объекта. Ведь тогда эту операцию можно использовать для смещения осей. Для ее реализации необходимо перегрузить оператор"+" еще раз, например, так:

//Перегружаем бинарный оператор "+" для суммирования

//объектаи int-значения.

public static ThreeD operator +(ThreeD opl, int op2)

{ThreeD result = new ThreeD();

result.x = opl.x + op2;

result.у = opl.у + op2;

result. z = opl. z + op2;

return result;}

Обратите вниман ие на то, что второй параметр имеет тип int. Таким образом,этот метод позволяет сложить int-значение с каждым полем ThreeD-объекта. Это вполне допустимо, поскольку, как разъяснялось выше, при перегрузке бинарного оператора тип только одного из его операндо в должен совпадать с типом класса, для которого перегружается этот оператор. Другой операнд может иметь любой тип.

Ниже приведена версия класса ThreeD, которая имеет два перегруженных метода operator+().

/* Перегрузка оператора сложения для вариантов:объект + объект и объект + int -значение. */

usingSystem;

// Класс трехмерных координат, classThreeD {

int x, у, z; // 3 -х-мерные координаты. publicThreeD() { х = у = z = 0; }

publicThreeD(int i, int j, int k) {x = i; у = j; z = k; }

//Перегружаем бинарный оператор " + " для варианта

//"объект + объект".

public static ThreeD operator +(ThreeD opl, ThreeD op2) {ThreeDresult = newThreeD();

/* Суммирование координат двух точеки возврат результата. */ result.x = opl.x + op2.x;

result.у = opl.y + op2.y; result. z = opl. z + op2.z; return result;}

//Перегружаем бинарный оператор "+" для варианта

//"объект + int-значение".

public static ThreeD operator +(ThreeD opl, int op2)

{

ThreeD result = new ThreeD(); result.x = opl.x + op2;

result.у = opl.y + op2; result. z = opl. z + op2;

return result;}

// Отображаемкоординаты X, Y, Z. public void show()

{

Console.WriteLine(x + ", " + у + ", " + z);

}

}

classThreeDDemo { public static void Main() {

ThreeD a = new ThreeD(1, 2, 3); ThreeD b = new ThreeD (10, 10, 10); ThreeD с = new ThreeD();

Console.Write(" Координатыточкиа : " ) ; a.show();

Console.WriteLine();

Console.Write(" Координатыточки b: " ) ; b.show();

Console.WriteLine();

с = a + b; // объект + объект

Console.Write("Результат сложения а + b: " ) ;

с.show();

Console.WriteLine();

с = b + 10; // объект + int -значение

Console.Write("Результат сложения b + 10: " ) ;

с.show();

}}

При выполнении программа генерирует следующие результаты:

Координаты точки а: 1, 2, 3

Координаты точки b: 10, 10, 10

Результат сложения а + b: 11, 12, 13

Результат сложения b + 10: 20, 20, 20

3. Генерирование исключений программно, Повторное генерирование исключений

Помимо генерации исключений генерируемых средствами С#, можно сгенерировать исключение программно, используя инструкцию throw. Формат ее записан таков:

throwexceptOb;

Элемент exceptOb — это объект класса исключений, производного от классаException.

Рассмотрим пример, который демонстрирует использование инструкции throw для генерирования исключения типа

DivideByZeroException программно.

.

usingSystem; // Генерирование исключения вручную

classThrowDemo {

public static void Main() {

try {

Console.WriteLine("До генерирования исключения.");

throw new DivideByZeroException();

}

catch (DivideByZeroException) { // Перехватываемисключение .

Console.WriteLine(" Исключениеперехвачено .");

}

Console.WriteLine("После try/catch -блока.");

}}

Результаты выполнения этой программ ы имеют такой вид:

До генерирования исключения.

Исключение перехвачено.

После try/catch -блока.

Объект исключения типа DivideByZeroException , создан

с

помощью оператора new в инструкции throw.

 

При создании объекта класса DivideByZeroException использовался конструктор по умолчанию, но для генерирования исключений предусмотрены и другие конструкторы.

Чаще всего генерируемые исключения являются экземплярами классов исключений, создаваемых в программе.

7.7 Повторное генерирование исключений

Исключение, перехваченное одной catch-инструкцией, можно

перегенерировать,чтобы обеспечить возможность его перехвата другой (внешней) catch-инструкцией.Самая распространенная причина для повторного генерирования исключения — позволить нескольким обработчикам по лучить доступ к исключению. Например, возможна такая ситуация, что один обработчик исключений управляет одним аспектомисключения, а второй — другим. Чтобы повторно сгенерировать исключение, достаточно использовать ключевое слово throw, не указывая исключения. Другими словами, используйте следующую форму инструкции throw,

throw;

При повторном генерировании исключения оно не будет повторноперехватываться той же catch-инструкцией, а передается следующей catch-инструкции.

using System;

class Rethrow {

public static void genException()

{ / / Здесьмассивnumerдлиннеемассиваdenom.

in t[] numer = { 4, 8, 16, 32, 64, 128, 256, 512 };

in t[] denom = { 2 , 0 , 4, 4, 0 , 8 };

for(int i=0; i<numer.Length; i++){

try {

Console.WriteLine(numer[i] + " / " + denom[i] + " равно " + numer[l]/denom[i]);

}

catch (DivideByZeroException) {// Перехватываемисключение .

Console.WriteLine(" Делитьнанульнельзя!")

}

catch (IndexOutOfRangeException) { // Перехватываемисключение .

Console.WriteLine(" Нетсоответствующегоэлемента .")

throw; // Генерируемисключениеповторно .

}}}}

class RethrowDemo {

public static void Main() {

try { Rethrow.genException(); }

catch(IndexOutOfRangeException) {

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

Console.WriteLine("Неисправимая

ошибка

—"программа

завершена.");

 

 

}}}

В этой программе ошибки деления на нуль обрабатываются локально (по месту),т.е. в самом методе genException (), но ошибка нарушения границ массива генерируется повторно. В данном случае исключение типа IndexOutOfRangeException обрабатывается функцией

Main().

4. Данные класса_ поля и константы

Данные, содержащиеся в классе, могут быть переменными или константами. Переменные, описанные в классе, называются полями класса.

При описании элементов класса можно также указывать атрибут ы и спецификаторы, задающие различные характеристики элементов. Синтаксис описания эле мента данных приведен ниже:

[ атрибуты ] [ спецификаторы ] [ const ] тип имя [ = начальное_значение ] Возможные спецификаторы полей и констант перечислены в табл.

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