Введение в ООП с примерами на C#. Часть четвёртая. Абстрактные классы
28К открытий28К показов
Рассказывает Akhil Mittal
В прошлых статьях серии “Введение в ООП” мы рассматривали полиморфизм (а также его нюансы на практике) и наследование. В этой мы поговорим о самой захватывающей части ООП-парадигмы — об абстрактных классах. В целом концепция абстрактных классов в C# ничем не отличается от таковой в других языках, но в C# работать с ней приходится несколько иначе.
Что такое абстрактные классы
В плане терминологии давайте доверимся MSDN:
Модификатор abstract указывает, что реализация сущности с данным модификатором является неполной или отсутствует. Модификатор abstract может использоваться с классами, методами, свойствами, индексаторами и событиями. Модификатор abstract в объявлении класса указывает, что класс предназначен только для использования в качестве базового класса для других классов. Члены, помеченные как абстрактные или включенные в абстрактный класс, должны быть реализованы с помощью классов, производных от абстрактных классов.
Абстрактные классы в действии
Итак, попробуем создать абстрактный класс:
Попытаемся скомпилировать этот код:
Compile time error: Cannot create an instance of the abstract class or interface ‘InheritanceAndPolymorphism.ClassA’
Что нужно запомнить: Мы не можем создать экземпляр абстрактного класса с помощью ключевого слова new
.
Описание методов в абстрактном классе
Попробуем добавить в наш абстрактный класс немного кода:
С кодом класса никаких проблем нет, но скомпилировать снова не получается, потому что нельзя создавать экземпляры абстрактных классов.
Использование абстрактного класса в качестве базового
Давайте попробуем создать ещё один класс:
Вау. Теперь всё спокойно компилируется.
Что нужно запомнить: Мы можем унаследовать обычный класс от абстрактного.
Что нужно запомнить: Мы можем создать экземпляр обычного класса, унаследованного от абстрактного, с помощью ключевого слова new
.
Декларация методов в абстрактном классе
Теперь попробуем сделать вот так:
И… мы получаем ошибку компиляции:
Compile time error: ‘InheritanceAndPolymorphism.ClassA.YYY()’ must declare a body because it is not marked abstract, extern, or partial
Дело в том, что если мы объявляем метод в абстрактном классе и при этом хотим, чтобы его конкретное поведение было определено в производных классах, то к такому методу мы должны так же добавить ключевое слово abstract
. Добавим его:
…и снова получим ошибку компиляции:
Compiler error: ‘InheritanceAndPolymorphism.ClassB’ does not implement inherited abstract member ‘InheritanceAndPolymorphism.ClassA.YYY()’
Что нужно запомнить: Если мы хотим объявить метод в абстрактном классе, но не реализовывать его, к методу нужно добавить ключевое слово abstract
.
Что нужно запомнить: Если мы объявляем абстрактный метод в абстрактном классе, то этот метод должен реализовываться в неабстрактных наследниках этого класса.
Реализация абстрактного метода в производном классе
Так, давайте тогда попробуем реализовать метод YYY()
в классе ClassB
:
На первый взгляд всё отлично, правда? Но на этот раз мы получим сразу две ошибки компиляции:
Compile time error: ‘InheritanceAndPolymorphism.ClassB’ does not implement inherited abstract member ‘InheritanceAndPolymorphism.ClassA.YYY()’
Дело в том, что в C# нужно явно объявить, что мы реализуем абстрактный метод класса-родителя с помощью ключевого слова override
:
Ура! ^_^ У нас наконец-то нет никаких ошибок!
Абстрактный метод базового класса и метод с override класса-наследника должны быть одинаковы
Это значит, что мы не можем менять тип возвращаемого значения или аргументы, которые передаются в метод. Например, если мы напишем такое:
То в консоли увидим следующую ошибку:
Compile time error: ‘InheritanceAndPolymorphism.ClassB.YYY()’: return type must be ‘void’ to match overridden member ‘InheritanceAndPolymorphism.ClassA.YYY()’
Инициализация переменных в абстрактных классах
В примерах выше, переменная int a
будет обладать значением по умолчанию (0). Мы можем изменить его на нужное нам прямо в абстрактном классе — с этим не связано никаких особенностей.
Абстрактные методы в неабстрактных классах
Такой код не скомпилируется:
Compiler error: ‘InheritanceAndPolymorphism.ClassA.YYY()’ is abstract but it is contained in non-abstract class ‘InheritanceAndPolymorphism.ClassA’
Что нужно запомнить: Абстрактные методы могут быть объявлены только в абстрактных классах.
Вызов абстрактного метода родителя
Вывод:
Compile time error : Cannot call an abstract base member: ‘InheritanceAndPolymorphism.ClassA.YYY()’
Разумеется, мы не можем исполнить код, которого не существует.
Абстрактный класс, который наследуется от другого абстрактного класса
Вывод:
ClassA XXX ClassC XXX
Почему вывод именно такой, вы должны понимать из материалов третьей статьи этой серии.
Может ли абстрактный класс быть sealed
Проверим:
И получим ошибку:
Compile time error: ‘InheritanceAndPolymorphism.ClassA’: an abstract class cannot be sealed or static
Разумеется, абстрактный класс не может быть sealed
, т.к. он для того и создан, чтобы от него создавались производные классы.
Что нужно запомнить: Абстрактный класс не может иметь модификатор sealed
.
Что нужно запомнить: Абстрактный класс не может иметь модификатор static
.
Что мы узнали сегодня:
Что нужно запомнить
- Мы не можем создать экземпляр абстрактного класса с помощью ключевого слова
new
; - Мы можем унаследовать обычный класс от абстрактного;
- Мы можем создать экземпляр обычного класса, унаследованного от абстрактного, с помощью ключевого слова
new
; - Если мы хотим объявить метод в абстрактном классе, но не реализовывать его, к методу нужно добавить ключевое слово
abstract
; - Если мы объявляем абстрактный метод в абстрактном классе, то этот метод должен реализовываться в неабстрактных наследниках этого класса;
- Абстрактные методы могут быть объявлены только в абстрактных классах;
- Абстрактный класс не может иметь модификатор
sealed
; - Абстрактный класс не может иметь модификатор
static
.
28К открытий28К показов