Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Программирование / Конспект лекций (C#).pdf
Скачиваний:
864
Добавлен:
27.05.2015
Размер:
2.03 Mб
Скачать

4.3.2 Абстрактные классы и члены классов

Рассматривая разработанную выше иерархию классов можно отметить, что класс Figure фактически служит только для того, чтобы на основе его создать порождённые классы. Создание объекта такого класса не имеет смысла. Кроме того, в методе Area данного класса потребовалось возвращать какое-нибудь значение (возвращается 0), хотя рассчитывать площадь неопределённой фигуры бессмысленно.

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

перед методом указывается модификатор abstact;

метод является виртуальным, но модификатор virtual в базовом классе не указывается;

абстрактный метод не может быть статическим (т.е. у него не может быть модификатора static);

в порождённом классе требуется указание модификатора override;

реализация абстрактного метода в базовом классе не требуется (да и не допу-

стима);

реализация абстрактного метода в порождённом классе обязательна, если дан-

ный класс не является абстрактным.

Если в классе имеется хотя бы один абстрактный метод, то весь класс стано-

вится абстрактным и в строке заголовка класса должен быть указан модификатор abstract. Однако класс может быть объявлен абстрактным, даже если он не имеет ни одного абстрактного метода.

Объект абстрактного класса не может быть создан.

Абстрактными также могут быть свойства и индексаторы.

Пример: модифицируем иерархию классов, сделав класс Figure и метод Area этого класса абстрактными.

abstract class Figure

{

...

public abstract double Area();

}

class Square : Figure

{

...

}

class Rectangle : Figure

{

...

}

Figure f; string s;

78

//f = new Figure(); Теперь данная строка недопустима f = new Square();

s = String.Format("{0}. Площадь: {1:N2}", f.sType, f.Area());

//s = "Квадрат. Площадь: 1,00"

f = new Rectangle();

s = String.Format("{0}. Площадь: {1:N2}", f.sType, f.Area());

// s = "Прямоугольник. Площадь: 4,00"

4.3.3 Операторы as и is

В предыдущем примере использовались возможности полиморфизма, позволяющие присвоить переменной класса Figure объекты порождённых классов:

Figure f = new Square();

Хотя мы и знаем, что в переменной f хранится ссылка на объект класса Square, обратиться к свойству size этого объекта без дополнительных преобразований будет невозможно, т.к. базовый класс не имеет такого свойства. Одним из возможных способов преобразования является приведение типов, которое может быть выполнено следующим образом:

((Square)f).size = 5;1

Однако явное преобразование при работе со ссылочными типами использовать не рекомендуется. Целесообразнее использовать специальный оператор преобразований ссылочных типов as, формальная схема которого имеет вид:

<объект> as <требуемый тип>

При помощи данного оператора присвоение вышеприведённый пример работы со свойством size может быть записан следующим образом:

(f as Square).size = 5;

Если преобразование выполнить невозможно, то возвращается null, напри-

мер:

public class Class1 {}

public class Class2 : Class1 {} public class Class3 : Class1 {}

Class2 cl2 = new Class2(); Class3 cl3 = new Class3(); Class1 cl1;

Class2 cl; cl1 = cl2;

cl = cl1 as Class2;

1 Строка (Square)f.size = 5; будет неправильной, т.к. операция обращения к члену класса выполняется ранее операции приведения типа

79

if (cl != null) // Истина

textBox1.Text = cl.ToString();// Выполняется эта строка else

textBox1.Text = "null"; cl1 = cl3;

cl = cl1 as Class2;

if (cl != null) // Ложь textBox2.Text = cl.ToString();

else

textBox2.Text = "null"; // Выполняется эта строка

Ещё одним оператором, используемым при работе с ссылочными типами, является оператор is, используемый для проверки принадлежности объекта к заданному типу1. Формальная схема данного оператора имеет вид:

<объект> is <проверяемый тип>

Оператор возвращает true, если объект может быть преобразован к проверяемому типу и false в противном случае (в том числе, если переменная имеет зна-

чение null). При проверке рассматривается внутреннее устройство объекта, а не тип переменной, которая проверяется.

Пример: имеется массив, каждый элемент которого может хранить ссылку на объект класса, порождённого от класса Figure. Требуется присвоить свойству size каждого объекта класса Square значение 3, а свойствам size1 и size2 каждого объекта класса Rectangle значения 4 и 5 соответственно.

Figure[] mas = new Figure[???]; for (int i=0; i<mas.Length; i++)

mas[i] = ???;

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

{

if (mas[i] is Square)

(mas[i] as Square).size = 3; else

if (mas[i] is Rectangle)

{

(mas[i] as Rectangle).size1 = 4; (mas[i] as Rectangle).size2 = 5;

}

}

Как видно из примера, использование возможностей полиморфизма, а также операторов as и is позволяет производить обработку объектов разных (но имеющих единого родителя) классов единообразно.

1 Правильнее сказать, что оператор is проверяет возможность преобразования. Для точной проверки сравнивается результат запроса типа объекта с помощью метода Object.GetType() с результатом получения типа с помощью оператора typeof(<тип>). Если типы совпадают, то оба результата должны ссылаться на один и тот же объект типа System.Type.

80