
- •Лекции по курсу "Технология программирования" (1-й семестр) Оглавление
- •Технология .Net Предыдущее состояние дел.
- •Главные компоненты платформы .Net (clr, cts и cls)
- •Общеязыковая среда выполнения (clr)
- •О бщая система типов и общеязыковые спецификации (cts и cls)
- •Библиотека базовых классов
- •Роль языка с#
- •Компоновочные блоки
- •Роль метаданных типов .Net
- •Роль манифеста компоновочного блока
- •Общая система типов.
- •Объектно-ориентированное программирование
- •Главные элементы объектно-ориентированного подхода
- •Дополнительные элементы ооп
- •Принципы объектно-ориентированного программирования.
- •Классы Инкапсуляция
- •Объект (экземпляр класса).
- •Ключевое слово this
- •Отношения между объектами.
- •Основные отличительные особенности класса
- •Спецификаторы доступа
- •Состав класса
- •Поля класса
- •Доступ к полям
- •Статические и экземплярные переменные
- •Методы (функции-члены класса)
- •Переменное число параметров метода
- •Статические методы
- •Конструкторы
- •Закрытые конструкторы или классы без экземпляров
- •Статические конструкторы.
- •Деструкторы
- •Абстрактные методы и классы.
- •Свойства
- •Индексаторы
- •Статические классы
- •Частичные классы
- •Рекомендации по программированию
- •Наследование Понятие наследования в программировании
- •Типы наследования
- •Наследование реализации
- •Определение наследующих классов
- •Уровень доступа protected и internal
- •Ссылка на объект базового класса
- •Протоклассы
- •Предотвращение наследования с помощью ключевого слова sealed.
- •Отношения между классами
- •Абстрактные классы.
- •Класс object
- •Функциональные замыкания
- •Разработка функциональных замыканий с помощью наследования
- •Разработка функциональных замыканий с помощью экземпляров класса
- •Заключение.
- •Полиморфизм
- •Полиморфизм наследующих классов.
- •Переопределение методов родительского класса. Раннее связывание.
- •Виртуальные методы и их переопределение.
- •Как вызывают виртуальные методы
- •Виртуальные функции и принцип полиморфизма
- •Перегрузка.
- •Перегруженные конструкторы
- •Рекомендации программисту.
Абстрактные классы.
С наследованием тесно связан еще один важный механизм проектирования семейства классов - механизм абстрактных классов. Дело в том, что, как уже отмечалось выше, можно выделить наиболее общие характеристики нескольких классов и поместить их в один родительский класс, называемый протоклассом. Но создавать экземпляры из протоклассов часто оказывается не всегда имеет смысл только потому, что им не соответствуют никакие реальные объекты. Но иногда полезно создать базовый класс, определяющий только своего рода "пустой бланк", который унаследуют все производные классы, причем каждый из них заполнит этот "бланк" собственной информацией. Такой класс определяет только состав методов, которые производные классы должны реализовать, но сам, при этом, не обеспечивает никакой реализации этих методов. В подобной ситуации используются такие понятия как абстрактные методы.
Абстрактный метод создается с помощью модификатора abstract. Абстрактный метод не имеет тела и, следовательно, не реализуется базовым классом, а производные классы должны его обязательно переопределить. Абстрактный метод автоматически является виртуальным, однако использовать спецификатор virtual не нужно. Более того, если вы попытаетесь использовать два спецификатора одновременно, abstract и virtual, то компилятор выдаст сообщение об ошибке.
Если класс содержит один или несколько абстрактных методов, то его также нужно объявить как абстрактный класс, используя спецификатор abstract перед ключевым словом class. Поскольку абстрактный класс полностью не реализован, то и невозможно будет создать его экземпляр с помощью операции new. Если же производный класс наследует абстрактный класс, то он должен полностью или частично реализовать все абстрактные методы базового класса или также быть объявлен как абстрактный. Спецификатор abstract наследуется до тех пор, пока в производном классе не будут реализованы все абстрактные методы абстрактного класса.
Совершенно очевидно, что в основе любого класса всегда лежит абстракция данных. Но абстрактный класс позволяет описывать эту абстракцию, не вникая в детали ее реализации, ограничиваясь описанием только методов, которые можно выполнять над данными такого класса. Абстрактный класс служит только для порождения потомков. Они могут иметь множество потомков, частично или полностью реализующих абстрактные методы своего родительского класса. Абстрактный метод чаще всего рассматривается как виртуальный метод, переопределяемый потомком, и поэтому к нему применяется стратегия динамического связывания.
Рассмотрим конкретный пример, в котором приводится описание абстрактного класса фигуры и производных от него классов окружности и прямоугольника.
// Абстрактный класс фигуры
abstract class Figura
{
Color borderColor, // Цвет контура
fillColor; // Цвет закраски
public Figura(){ borderColor=Color.Black; fillColor=Color.Red; } // Конструктор
// Функции доступа к закрытым данным:
public void SetBColor(Color c);
public void SetFColor(Color c);
// Абстрактные функции, реализация которых будет зависеть от порождаемых классов:
public abstract void Draw(Graphics g);
public abstract void Move(int dx, int dy);
}
class Circle : Figura
{
// Собственные переменные:
Point pnt; // Положение центра окружности
int radius; // Радиус окружности
// Конструктор по умолчанию:
public Circle(){ pnt = new Point(200,200); radius=100; }
// Абстрактные функции базового класса, которые необходимо реализовать:
public override void Draw(Graphics g) //Реализация функции рисования
{
…
g.DrawCircle(…);
…
}
public override void Move(int dx, int dy) // Реализация функции перемещения
{ pnt.offset(dx, dy); }
}
class Rect : Figura
{
// Собственные данные:
Point p1, p2; // Положение левой-верхней и правой-нижней вершин прямоугольника
// Конструктор по умолчанию:
public Rect() { p1 = new Point(100,100); p2 = new Point(200,200); }
// Абстрактные функции базового класса, которые необходимо реализовать:
public override void Draw(Graphics g) // Собственная реализация функции рисования
{
…
g.DrawRectangle(…);
…
}
public override void Move(int dx, int dy) // Собственная реализация функции перемещения
{ p1.offset(dx, dy); p2.offset(dx, dy); }
}
Как видно из листинга, абстрактный класс фигуры содержит две переменные, конструктор и два абстрактных метода Draw и Move. Этот класс создан для того, чтобы порождать от него другие классы, характеризующие разные геометрические фигуры. В данном случае это классы описания объектов типа окружности и прямоугольника. Поскольку заранее невозможно определить какой из методов будет использоваться порождаемыми классами для своего вырисовывания или перемещения, то в базовом классе фигуры эти методы объявляются абстрактными. Но поскольку класс содержит абстрактные методы, то и сам класс объявляется как абстрактный.
Порождая производные классы окружности и прямоугольника от абстрактного класса фигуры мы с помощью модификатора override переопределяем в каждом из них абстрактные методы Draw и Move, описывая в их телах конкретную реализацию, учитывающую специфику порождаемого класса. Теперь в объявлениях классов окружности и прямоугольника можно убрать спецификатор abstract, сообщая тем самым о том, что теперь они являются полностью определенными классами, которые можно использовать для создания объектов.
Итак, подведем итоги. Класс называется абстрактным, если он имеет, хотя бы один, абстрактный метод. Метод называется абстрактным, если при определении метода задана только его сигнатура и не задана его реализация. Объявление абстрактных методов и абстрактных классов должно сопровождаться модификатором abstract. Поскольку абстрактные классы не являются полностью определенными классами, то нельзя создавать объекты абстрактных классов. При переопределении абстрактного метод базового класса в производном классе необходимо переопределить его с указанием модификатора override.