Что такое абстрактный класс
Абстрактные классы
Абстрактные классы — это классы, которые оставляют некоторые или все элементы нереализованными, чтобы реализации могли предоставляться производными классами.
Синтаксис
Remarks
В объектно-ориентированном программировании абстрактный класс используется в качестве базового класса иерархии и представляет общие функциональные возможности различных наборов типов объектов. Как предполагает имя «abstract», абстрактные классы часто не соответствуют конкретным сущностям в области, в которой возникла проблема. Однако они показывают, сколько различных конкретных сущностей встречается чаще всего.
Как и в случае с другими типами, абстрактные классы могут иметь базовый класс и один или несколько базовых интерфейсов. Каждый базовый класс или интерфейс отображается в отдельной строке вместе с inherit ключевым словом.
В следующем коде показана абстрактная фигура класса, которая имеет два неабстрактных производных класса: квадратные и круговые. В примере показано, как использовать абстрактные классы, методы и свойства. В примере фигура абстрактного класса представляет общие элементы конкретных сущностей Circle и Square. Общие функции всех фигур (в двухмерной системе координат) являются абстрактными в классе Shape: положение в сетке, угол поворота, а также свойства области и периметра. Они могут быть переопределены, за исключением расположения, поведения отдельных фигур, которые не могут изменяться.
Метод вращения можно переопределить, как в классе Circle, который является неизменяемым в связи с его симметрией. Поэтому в классе Circle метод вращения заменяется методом, который ничего не делает.
ООП. Часть 6. Абстрактные классы и интерфейсы
Узнайте истинную мощь наследования и полиморфизма! Раскрываем секреты абстрактных классов и интерфейсов.
В предыдущей статье мы увидели, насколько удобнее становится ООП благодаря наследованию. Но оно может стать ещё лучше, если использовать абстрактные классы и интерфейсы.
Все статьи про ООП
Пишет о программировании, в свободное время создает игры. Мечтает открыть свою студию и выпускать ламповые RPG.
Абстрактные классы
Особенность абстрактных классов в том, что их можно использовать только как родительский класс, то есть вы не можете создать объект. Для их объявления используется ключевое слово abstract.
Это может понадобиться, чтобы объединить реализацию других схожих классов. Например, в вашей игре должны быть персонаж игрока и NPC (неигровые персонажи). У них могут быть общие свойства (имя, координаты) и методы (перемещение, изменение анимации).
Чтобы не повторять код несколько раз, можно вынести реализацию этих свойств и методов в абстрактный класс Character:
Тут всё как у обычных классов, но в конце можно заметить объявление свойства и метода без реализации. Реализация этих абстрактных свойств должна находиться в дочернем классе:
Когда объявляется реализация такого члена класса, необходимо указать ключевое слово override. Абстрактными могут быть следующие члены класса:
Дочерний класс должен реализовывать все члены родительского абстрактного класса, кроме тех случаев, когда дочерний класс тоже абстрактный.
В остальном всё очень похоже на обычные классы. Например, поле Y класса Character публичное, чтобы можно было использовать его в свойстве Y дочерних классов.
Абстрактный класс должен быть публичным.
Введение в ООП с примерами на C#. Часть четвёртая. Абстрактные классы
В прошлых статьях серии «Введение в ООП» мы рассматривали полиморфизм (а также его нюансы на практике) и наследование. В этой мы поговорим о самой захватывающей части ООП-парадигмы — об абстрактных классах. В целом концепция абстрактных классов в C# ничем не отличается от таковой в других языках, но в C# работать с ней приходится несколько иначе.
Что такое абстрактные классы
В плане терминологии давайте доверимся MSDN:
Модификатор abstract указывает, что реализация сущности с данным модификатором является неполной или отсутствует. Модификатор abstract может использоваться с классами, методами, свойствами, индексаторами и событиями. Модификатор abstract в объявлении класса указывает, что класс предназначен только для использования в качестве базового класса для других классов. Члены, помеченные как абстрактные или включенные в абстрактный класс, должны быть реализованы с помощью классов, производных от абстрактных классов.
Абстрактные классы в действии
Итак, попробуем создать абстрактный класс:
Попытаемся скомпилировать этот код:
Compile time error: Cannot create an instance of the abstract class or interface ‘InheritanceAndPolymorphism.ClassA’
Описание методов в абстрактном классе
Попробуем добавить в наш абстрактный класс немного кода:
С кодом класса никаких проблем нет, но скомпилировать снова не получается, потому что нельзя создавать экземпляры абстрактных классов.
Использование абстрактного класса в качестве базового
Давайте попробуем создать ещё один класс:
Вау. Теперь всё спокойно компилируется.
Что нужно запомнить: Мы можем унаследовать обычный класс от абстрактного.
Декларация методов в абстрактном классе
Теперь попробуем сделать вот так:
И… мы получаем ошибку компиляции:
Compile time error: ‘InheritanceAndPolymorphism.ClassA.YYY()’
must declare a body because it is not marked abstract, extern, or partial
…и снова получим ошибку компиляции:
Compiler error: ‘InheritanceAndPolymorphism.ClassB’ does not implement
inherited abstract member ‘InheritanceAndPolymorphism.ClassA.YYY()’
Что нужно запомнить: Если мы объявляем абстрактный метод в абстрактном классе, то этот метод должен реализовываться в неабстрактных наследниках этого класса.
Реализация абстрактного метода в производном классе
Так, давайте тогда попробуем реализовать метод YYY() в классе ClassB :
На первый взгляд всё отлично, правда? Но на этот раз мы получим сразу две ошибки компиляции:
Compile time error: ‘InheritanceAndPolymorphism.ClassB’ does not implement
inherited abstract member ‘InheritanceAndPolymorphism.ClassA.YYY()’
Compile time warning: ‘InheritanceAndPolymorphism.ClassB.YYY()’ hides
inherited 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()’
Разумеется, мы не можем исполнить код, которого не существует.
Абстрактный класс, который наследуется от другого абстрактного класса
Почему вывод именно такой, вы должны понимать из материалов третьей статьи этой серии.
Может ли абстрактный класс быть sealed
Compile time error: ‘InheritanceAndPolymorphism.ClassA’:
an abstract class cannot be sealed or static
Что мы узнали сегодня:
Что нужно запомнить
Абстрактные и запечатанные классы и члены классов (Руководство по программированию на C#)
Ключевое слово abstract позволяет создавать классы и члены классов, которые являются неполными и должны быть реализованы в производном классе.
Ключевое слово sealed позволяет предотвратить наследование класса или определенных членов класса, помеченных ранее как virtual.
Абстрактные классы и члены классов
Классы могут быть объявлены абстрактными путем помещения ключевого слова abstract перед определением класса. Пример:
Создавать экземпляры абстрактного класса нельзя. Назначение абстрактного класса заключается в предоставлении общего определения для базового класса, которое могут совместно использовать несколько производных классов. Например, в библиотеке классов может быть определен абстрактный класс, используемый в качестве параметра для многих из ее функций, поэтому программисты, использующие эту библиотеку, должны задать свою реализацию этого класса, создав производный класс.
Абстрактные методы не имеют реализации, поэтому определение такого метода заканчивается точкой с запятой вместо обычного блока метода. Классы, производные от абстрактного класса, должны реализовывать все абстрактные методы. Если абстрактный класс наследует виртуальный метод из базового класса, абстрактный класс может переопределить виртуальный метод с помощью абстрактного метода. Пример:
Запечатанные классы и члены классов
Классы могут быть объявлены как запечатанные путем помещения ключевого слова sealed перед определением класса. Пример:
Запечатанный класс не может использоваться в качестве базового класса. Поэтому он также не может быть абстрактным классом. Запечатанные классы предотвращают наследование. Поскольку их нельзя использовать в качестве базовых классов, определенная оптимизация во время выполнения позволяет несколько ускорить вызов членов запечатанных классов.
Абстрактные классы (C++)
Абстрактные классы используются в качестве обобщенных концепций, на основе которых можно создавать более конкретные производные классы. Нельзя создать объект типа абстрактного класса. Однако можно использовать указатели и ссылки на абстрактные типы классов.
Абстрактный класс создается путем объявления по крайней мере одной чистой виртуальной функции члена. Это виртуальная функция, объявленная с помощью синтаксиса чистого описателя ( ). Классы, производные от абстрактного класса, должны реализовывать чисто виртуальную функцию; в противном случае они также будут абстрактными.
Рассмотрим пример, представленный в виртуальных функциях. Класс Account создан для того, чтобы предоставлять общие функции, но объекты типа Account имеют слишком общий характер для практического применения. Это означает Account хороший кандидат для абстрактного класса:
Единственное различие между этим и предыдущим объявлениями состоит в том, что функция PrintBalance объявлена со спецификатором чисто виртуальной функции pure ( = 0 ).
Ограничения на использование абстрактных классов
Абстрактные классы нельзя использовать для:
переменных и данных членов;
типов возвращаемых функциями значений;
типов явных преобразований.
Если конструктор абстрактного класса вызывает чисто виртуальную функцию, прямо или косвенно, результат не определен. Однако конструкторы и деструкторы абстрактных классов могут вызывать другие функции-члены.
Определенные чистые виртуальные функции
Чистые виртуальные функции в абстрактных классах могут быть определеныили иметь реализацию. Вызывать эти функции можно только с помощью полного синтаксиса:
abstract — имя класса::Function-Name()
Определенные чистые виртуальные функции полезны при проектировании иерархий классов, базовые классы которых содержат чистые виртуальные деструкторы. Это обусловлено тем, что деструкторы базового класса всегда вызываются во время уничтожения объекта. Рассмотрим следующий пример.
В примере показано, как расширение компилятора Майкрософт позволяет добавить встроенное определение в чистый виртуальный
Когда объект aDerived выходит из области действия, derived вызывается деструктор класса. Компилятор создает код для неявного вызова деструктора класса base после derived деструктора. Пустая реализация чисто виртуальной функции
base гарантирует, что для функции существует хотя бы определенная реализация. Без него компоновщик создает неразрешенную ошибку внешнего символа для неявного вызова.
В предыдущем примере чистая виртуальная функция base::
base вызывается неявно из derived::