lec
.pdfвыполнения нет деления объекта на предка и потомка – это единый объект.
Агрегация – аналог производства изделия методом «отверточной сборки». Изготовленные по отдельным чертежам детали (объекты) собираются в более сложное изделие (объект). Класс-контейнер – это сборочный чертеж изделия, определяющий его составные части. На этапе выполнения сохраняется четкое деление объекта на контейнер и часть. Это самостоятельные объекты.
Владелец |
|
Человек |
|
|
|
чел |
|
фам |
ном |
|
|
|
|
|
|
|
|
Инфо() |
|
Показать() |
|
|
|
|
|
2 |
|
1 |
|
|
|
Создать объект |
|
Создать объект |
|
|
100 |
А777АА-99RUS |
Инфо() |
«Петров» |
Показать() |
3 |
включить объект |
|
100 |
|
|
|
|
|
Рис.5
class Человек
{
public string фам;
public Человек(string фам)
{
this.фам = фам;
}
public void Показать()
{
Console.WriteLine("Я - человек: " + фам);
}
}
class Владелец
{
public Человек чел; private string ном;
public Владелец(Человек чел, string ном)
{
this.чел = чел; this.ном = ном;
}
131
public void Инфо()
{
Console.WriteLine("Я - владелец: "+чел.фам+" --> " + ном);
}
}
class Program
{
static void Main(string[] args)
{
Человек ч = new Человек("Петров");
Владелец вл = new Владелец(ч,"A777AA-99RUS");
вл.чел.Показать(); //Я - человек: Петров
вл.Инфо();
//Я - владелец: Петров --> A777AA-99RUS
}
}
3. Наследование как средство изменения базового класса
Реализуется через переопределение полей, методов и свойств базового класса в классе-потомке. На практике чаще всего используется изменение поведения – т.е. переопределение методов.
Синтаксически это реализуется как определение в классе-потомке метода с тем же именем, составом параметров и возвращаемым значением, что и в базовом классе.
ссылка |
|
|
|
ссылка |
|
|
Класс 1 |
||||
100 |
|
|
|
200 |
|
|
|
|
|
||
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int |
F (int x) {…} |
|
|
|
|
|
|
|
|
ссылка |
|
|
|
|
ссылка |
|
Класс 2 |
|
Класс 3 |
|
|||
100 |
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
200 |
|
|
|
|
|
|
|
|
|
|
|
|
|
||
|
|
|
|
|
|
|
|
|
new int F (int x) {…} |
|
override int F (int x) {…} |
|
|
|
|
|
|
|
|
|
Создать объект
ОБЪЕКТ
100
Создать объект
ОБЪЕКТ
200
Рис.6
132
С# поддерживает два способа переопределения метода, определенного в базовом классе на метод, определенный в классе-потомке (Рис.6):
1.new – новая версия метода. Решение о вызываемом методе принимается по типу ссылки. Через ссылку класса-предка вызывается метод, определенный в классе предке, а через ссылку класса-потомка вызывается метод, определенный в классе-потомке.
2.override – метод, заменяющий метод предка. Метод может быть вызван через ссылку класса-потомка или ссылку базового класса. Решение
овызываемом методе принимается по типу объекта, на который указывает ссылка. Для реализации этого способа метод в классе-предке должен быть объявлен как виртуальный (virtual).
class Человек
{
protected string фам; public Человек(string фам)
{
this.фам = фам;
}
public virtual void Показать()
{
Console.WriteLine("Я - человек: " + фам);
}
}
class Студент:Человек
{
private string вуз;
public Студент(string фам, string вуз):base(фам)
{
this.вуз = вуз;
}
}
class Владелец: Человек
{
private string ном;
public Владелец(string фам, string ном): base(фам)
{
this.ном = ном;
}
public new void Показать()
{
Console.WriteLine("Я - владелец: " + фам + " --> " + ном);
}
}
class Служащий: Человек
{
private string фирма;
public Служащий(string фам, string фирма): base(фам)
{
this.фирма = фирма;
}
133
public override void Показать()
{
Console.WriteLine("Я - служащий: "+фам +" ____ "+ фирма);
}
}
class Program
{
static void Main(string[] args)
{
Человек ч;
Студент ст = new Студент("Иванов","ВШЭ");
Владелец вл = new Владелец("Петров", "A777AA-99RUS"); Служащий сл = new Служащий("Сидоров", "Рога и копыта");
ч = ст; |
//Вызов метода предка |
ч.Показать(); |
|
//Я - человек: |
Иванов |
ст.Показать(); |
//Вызов метода предка |
//Я - человек: Иванов |
|
ч = вл; |
//Вызов метода предка |
ч.Показать(); |
|
//Я - человек: |
Петров |
вл.Показать(); |
//Вызов метода наследника |
//Я - владелец: Петров --> A777AA-99RUS |
|
ч = сл; |
//Вызов метода наследника |
ч.Показать(); |
//Я - служащий: Сидоров ____ Рога и копыта сл.Показать(); //Вызов метода наследника //Я - служащий: Сидоров ____ Рога и копыта
}
}
Применение вызова переопределенного метода override позволяет просто решить проблему определения вызываемого метода при хранении в массиве объектов разного типа. Массив организуется как массив ссылок базового типа. Вызываемый метод определяется автоматически по типу объекта, на который указывает ссылка.
Метод в базовом классе может быть объявлен как абстрактный. Такой метод не содержит реализации – тела. Это только заголовок. Другими словами, базовый класс только декларирует общее поведение, а реализовать его обязаны потомки. В этом отличие абстрактных методов от виртуальных. Виртуальный метод может, но не обязан быть переопределен в потомках. Абстрактный метод должен быть переопределен в клас- се-потомке в обязательном порядке.
Класс, содержащий хотя бы один абстрактный метод, является абстрактным, о чем должно быть указано в определении класса
abstract class ИмяКласса
{
……………………………
}
134
Потомки обязаны переопределять абстрактный метод с модификатором override (new невозможно, т.к. у предка нет никакой версии реализации метода).
abstract class Человек
{
protected string фам; public Человек(string фам)
{
this.фам = фам;
}
public abstract void Показать();
}
class Студент:Человек
{
private string вуз;
public Студент(string фам, string вуз):base(фам)
{
this.вуз = вуз;
}
public override void Показать()
{
Console.WriteLine("Я - студент: " + фам + " " + вуз);
}
}
class Владелец: Человек
{
private string ном;
public Владелец(string фам, string ном): base(фам)
{
this.ном = ном;
}
public override void Показать()
{
Console.WriteLine("Я - владелец: " + фам + " --> " + ном);
}
}
class Служащий: Человек
{
private string фирма;
public Служащий(string фам, string фирма): base(фам)
{
this.фирма = фирма;
}
public override void Показать()
{
Console.WriteLine("Я - служащий: "+фам + " ____ " + фирма);
}
}
135
class Program
{
static void Main(string[] args)
{
Человек ч;
Студент ст = new Студент("Иванов","ВШЭ");
Владелец вл = new Владелец("Петров", "A777AA-99RUS"); Служащий сл = new Служащий("Сидоров", "Рога и копыта"); ч = ст; ч.Показать(); //Вызов метода наследника
//Я - студент: Иванов ВШЭ ст.Показать(); //Вызов метода наследника //Я - студент: Иванов ВШЭ
ч = вл; ч.Показать(); //Вызов метода наследника
//Я - владелец: Петров --> A777AA-99RUS
вл.Показать(); //Вызов метода наследника
//Я - владелец: Петров --> A777AA-99RUS
ч = сл; ч.Показать(); //Вызов метода наследника
//Я - служащий: Сидоров ____ Рога и копыта сл.Показать(); //Вызов метода наследника //Я - служащий: Сидоров ____ Рога и копыта
}
}
Объекты абстрактного класса создать невозможно.
136
ИСКЛЮЧЕНИЯ И ОТЛАДКА
1. Традиционные способы обработки ошибок. Понятие «Структурная обработка исключений».
Многие системные функции возвращают значение, указывающее на успешное или безуспешное выполнение функции. Однако такой способ извещения программы имеет ряд недостатков:
•Во-первых, программист обязан выполнять все проверки возвращаемого значения и либо реагировать на ошибки, либо передавать их на более высокий уровень программы. Если на одном из уровней проверка не проводится, то ошибки могут повлиять на другие части программы.
•Во-вторых, текст программы загромождается операторами if...else, обрабатывающими нетипичные случаи.
•В-третьих, информация о причине возникновения ошибки не всегда легко доступна коду, который должен обработать ошибку. К тому же функция не всегда способна предугадать появление всех ошибок, связанных с внешней средой.
Для доступа прикладных программ к информации о возникшем исключении в Windows (начиная с NT) разработан специальный механизм,
называемый структурной обработкой исключений.
Исключительная ситуация (или исключение) — это ошибка, ко-
торая возникает во время выполнения программы.
Структурная обработка исключений — это метод, применяемый
Windows для обработки как программных, так и внутренних аппаратных исключений.
Средство обработки исключений Windows не зависит от используемого языка программирования: один и тот же механизм используется для всех языков.
Каждый язык определяет, каким образом в нем реализуется этот механизм.
2. Организация обработки исключений в С#
Основная идея обработки исключений состоит в том, что в программе можно определить блок кода, именуемый обработчиком исключений, который автоматически будет получать управление при возникновении определенной ошибки. Обработчик исключений оформляется в виде catch-блока.
В этом случае не обязательно проверять результат выполнения каждой конкретной операции или метода вручную.
Программные инструкции, которые нужно проконтролировать на предмет исключений, помещаются в try-блок.
137
Программа |
|
Метод, |
|
|
|
CLR |
|
|
|
Ошибка |
|
|
|
Система динами- |
|
|
|
ческого управле- |
|
|
|
ния |
|
|
|
Аварийное |
|
Рис. 1. Без обработки исключения |
завершение |
||
Программа |
|
Метод, |
|
|
|
||
|
|
CLR |
|
try |
|
Ошибка |
|
{ |
Exception |
||
|
|||
} |
Система динами- |
|
|
|
|
||
catch |
ческого управле- |
|
|
ния |
|
||
{ |
|
|
|
} |
|
|
|
Рис.2. Обработка исключения |
|
||
Программа |
|
|
|
|
|
Метод |
|
try |
|
Исключений |
|
{ |
|
||
} |
|
нет |
|
|
|
||
catch |
|
|
|
{ |
|
|
|
} |
|
|
|
Рис.3 Безошибочное выполнение |
|
138
В С# исключения представляются классами, выведенными из встроенного класса исключений Exception.
Наследниками класса Exception являются классы SystemException и ApplicationException, которые делят исходные исключения на две группы.
Exception
SystemException ApplicationException
(генерирует CLR) |
(генерируют прикладные програм- |
|
мы) |
||
|
Формат записи try/catch-блоков: try
{
// Блок кода, подлежащий проверке на наличие ошибок.
} |
|
catch |
( ExcepType1 e ) |
{ |
|
// |
Обработчик исключения типа ExcepTypel. |
} |
|
catch ( ExcepType2 e )
{
// Обработчик исключения типа ЕхсерТуре2.
}
ЕхсерТуре — это тип сгенерированного исключения. е – экземпляр типа ЕхсерТуре.
Варианты catch-блоков: catch ( ExcepType )
{
// Обработчик исключения типа ExcepTypel.
}
catch ( IOException e )
{
// Обработчик всех исключений ввода-вывода
}
catch ( SystemException e )
{
139
// Обработчик всех системных исключений
}
catch ( Exception e )
{
//Обработчик всех исключений.
//Передается информация об исключении
}
catch ()
{
//Обработчик всех исключений.
//Информация об исключении не передается
}
Системные исключения класса SystemException
Производный класс |
Описание |
|
|
|
ArithmeticException |
Ошибка в арифметических операциях |
|||
|
или операциях преобразования (пре- |
|||
|
док |
DivideByZeroException |
и |
|
|
OverFlowException) |
|
||
ArrayTypeMismatchException |
Тип сохраняемого значения несо- |
|||
|
вместим с типом массива |
|
||
DivideByZeroException |
Попытка деления на нуль |
|
||
FormatException |
Попытка передать в метод аргумент |
|||
|
неверного формата |
|
||
IndexOutOfRangeException |
Индекс массива оказался вне диапа- |
|||
|
зона |
|
|
|
InvalidCastException |
Неверно |
|
выполнено динамическое |
|
|
приведение типов |
|
||
OutOfMemoryException |
Обращение к оператору new оказа- |
|||
|
лось неудачным из-за недостаточного |
|||
|
объема свободной памяти |
|
||
OverflowException |
Имеет место арифметическое пере- |
|||
|
полнение |
и используется оператор |
||
|
checked |
|
|
|
StackOverflowException |
Переполнение стека |
|
||
NullReferenceException |
Была сделана попытка использовать |
|||
|
нулевую ссылку, т.е. ссылку, которая |
|||
|
не указывает ни на какой объект |
|
||
IOException |
Ошибка ввода-вывода |
|
||
TypeInitializationExeption |
Отсутствует блок catch для обработки |
|||
|
исключения, сгенерированного ста- |
|||
|
тическим конструктором |
|
3. Свойства и методы класса Exception
140