Абстрактные классы (C++)
Абстрактные классы используются в качестве обобщенных концепций, на основе которых можно создавать более конкретные производные классы. Нельзя создать объект типа абстрактного класса. Однако можно использовать указатели и ссылки на абстрактные типы классов.
Абстрактный класс создается путем объявления по крайней мере одной чистой виртуальной функции члена. Это виртуальная функция, объявленная с помощью синтаксиса чистого описателя ( = 0 ). Классы, производные от абстрактного класса, должны реализовывать чисто виртуальную функцию; в противном случае они также будут абстрактными.
Рассмотрим пример, представленный в виртуальных функциях. Класс Account создан для того, чтобы предоставлять общие функции, но объекты типа Account имеют слишком общий характер для практического применения. Это означает Account хороший кандидат для абстрактного класса:
Единственное различие между этим и предыдущим объявлениями состоит в том, что функция PrintBalance объявлена со спецификатором чисто виртуальной функции pure ( = 0 ).
Ограничения на использование абстрактных классов
Абстрактные классы нельзя использовать для:
переменных и данных членов;
типов возвращаемых функциями значений;
типов явных преобразований.
Если конструктор абстрактного класса вызывает чисто виртуальную функцию, прямо или косвенно, результат не определен. Однако конструкторы и деструкторы абстрактных классов могут вызывать другие функции-члены.
Определенные чистые виртуальные функции
Чистые виртуальные функции в абстрактных классах могут быть определены или иметь реализацию. Вызывать эти функции можно только с помощью полного синтаксиса:
abstract — имя класса::Function-Name()
Определенные чистые виртуальные функции полезны при проектировании иерархий классов, базовые классы которых содержат чистые виртуальные деструкторы. Это обусловлено тем, что деструкторы базового класса всегда вызываются во время уничтожения объекта. Рассмотрим следующий пример.
В примере показано, как расширение компилятора Майкрософт позволяет добавить встроенное определение в чистый виртуальный
Когда объект aDerived выходит из области действия, derived вызывается деструктор класса. Компилятор создает код для неявного вызова деструктора класса base после derived деструктора. Пустая реализация чисто виртуальной функции
base гарантирует, что для функции существует хотя бы определенная реализация. Без него компоновщик создает неразрешенную ошибку внешнего символа для неявного вызова.
В предыдущем примере чистая виртуальная функция base::
base вызывается неявно из derived::
Создание объекта абстрактного класса
Хотел в качестве применения protected конструктора привести класс java.util.Calendar. Но для начала посмотрел в исходники и, с удивлением, обнаружил, что этот класс является абстрактным. Всегда считал, что нельзя создать экземпляр абстрактного класса. Но получить объект класса Calendar можно с помощью
В чем же тогда суть запрета создавать экземпляр абстрактного класса? Я просто не могу написать в коде new Calendar()? А через какие-то другие методы могу спокойно получить экземпляр такого класса? То есть верно ли утверждение, что «если класс является абстрактным, то его конструктор по умолчанию является protected»?
2 ответа 2
Если ты заглянешь в реализацию getInstance, то увидишь, что этот метод вызывает другой статичный метод createCalendar, а уже он создает не объекты абстрактного класса Calendar, а объекты наследников этого класса, например BuddhistCalendar. Так как BuddhistCalendar наследует Calendar, то позволяется неявное приведение к этому типу.
Давайте проведём различие между заявленным и реальным типом объекта. Ссылка, которая у вас есть, ссылается на заявленный тип, тип, известный при компиляции. А вот реальный тип объекта при этом может быть любым производным от заявленного типа.
Теперь назад, к теме вопроса. Вы таки не можете иметь экземпляр с реальным типом, соответствующим абстрактному классу. Потому что такой объект просто нельзя сконструировать. А вот заявленный тип Calendar означает, что реально там или Calendar (что невозможно, т. к. он абстрактный), или любой производный от него тип.
Получаем вывод (в моём случае) java.util.GregorianCalendar[. — экземпляр производного типа.
Суть запрета на создание абстрактного класса заключается в том, что этот класс не окончен, и должен быть окончен в порождённых классах. Например, в нём отсутствуют какие-то методы. Раз этот класс не готов к использованию, то и создавать его нельзя. А вот законченные, готовые к использованию порождённые классы можно инстанциировать.
Абстрактные классы и методы
Класс, содержащий абстрактные методы, называется абстрактным классом. Такие классы помечаются ключевым словом abstract.
Абстрактный метод не завершён. Он состоит только из объявления и не имеет тела:
По сути, мы создаём шаблон метода. Например, можно создать абстрактный метод для вычисления площади фигуры в абстрактном классе Фигура. А все другие производные классы от главного класса могут уже реализовать свой код для готового метода. Ведь площадь у прямоугольника и треугольника вычисляется по разным алгоритмам и универсального метода не существует.
Если вы объявляете класс, производный от абстрактного класса, но хотите иметь возможность создания объектов нового типа, вам придётся предоставить определения для всех абстрактных методов базового класса. Если этого не сделать, производный класс тоже останется абстрактным, и компилятор заставит пометить новый класс ключевым словом abstract.
Можно создавать класс с ключевым словом abstract даже, если в нем не имеется ни одного абстрактного метода. Это бывает полезным в ситуациях, где в классе абстрактные методы просто не нужны, но необходимо запретить создание экземпляров этого класса.
В тоже время абстрактный класс не обязательно должен иметь только абстрактные методы. Напомню ещё раз, что если класс содержит хотя бы один абстрактный метод, то он обязан быть сам абстрактным.
Создавать объект на основе абстрактного класса нельзя.
Абстрактный класс не может содержать какие-либо объекты, а также абстрактные конструкторы и абстрактные статические методы. Любой подкласс абстрактного класса должен либо реализовать все абстрактные методы суперкласса, либо сам быть объявлен абстрактным. Короче, я сам запутался. Пойду лучше кота поглажу.
Я вернулся. Давайте напишем пример для абстрактного класса.
Допустим, мы хотим создать абстрактный класс СферическийКонь и не менее идиотский класс СферическийКоньВВакууме, наследующий от первого класса.
Когда вы напишете такой код, то студия подчеркнёт второй класс красной волнистой линией и предложит реализовать обязательный метод, который определён в абстрактном классе.
Соглашаемся и дописываем в созданную заготовку свой код для метода.
В главной активности напишем код для щелчка кнопки.
Обратите внимание, что абстрактный класс может содержать не только абстрактные, но и обычные методы.
Раннее мы создавали класс Фигура, у которого был метод вычисления площади фигуры. Метод ничего не делал, так как невозможно вычислить площадь неизвестной фигуры. Поэтому, этот метод можно сделать абстрактным, а в классах, производных от Фигуры, переопределить данный метод.
Вам вряд ли придётся часто создавать абстрактные классы для своих приложений, но встречаться с ними вы будете постоянно, например, классы AsyncTask, Service и др.
BestProg
Содержание
Поиск на других ресурсах:
1. Что такое абстрактный класс? Назначение абстрактных классов. Общая форма. Ключевое слово abstract
Абстрактный класс – это класс, содержащий методы, которые не имеют реализации. Абстрактный класс создается с целью создания общего интерфейса между разными реализациями классов, которые будут производными от абстрактного класса. Абстрактный класс создается для определения некоторых общих черт производных от него классов, которые определяют конкретную его реализацию.
Запрещено (нет смысла) создавать объект абстрактного класса.
Общая форма объявления абстрактного класса следующая:
2. Что такое абстрактный метод? Общая форма
Если некоторый класс есть унаследованным от абстрактного, то этот класс должен переопределить все абстрактные методы базового абстрактного класса. В противном случае будет сгенерирована ошибка.
Общая форма объявления абстрактного метода в абстрактном классе имеет следующий вид:
В иерархии наследования (расширения) классов, абстрактные методы являются чем-то общим. Конкретные реализации абстрактных методов помещаются классах, унаследованных от абстрактных классов.
3. Схематическое изображение объявления и использования абстрактного метода в абстрактном классе. Пример
Рисунок. Схема взаимодействия между абстрактным классом и производными классами в Java
4. Пример, который демонстрирует использование абстрактных классов
В классе Figure объявляются:
В классе Triangle() реализованы:
В результате выполнения функции main() класса UseAbstractClass будет выведен следующий результат:
5. Объяснение к примеру из пункта 4
Объяснение к примеру (см. предшествующий пункт) в виде вопросов.
5.1. Зачем в классе Figure методы Area() и ShowName() объявляются абстрактными?
5.2. Почему класс Figure объявляется абстрактным?
5.3. Почему в классе Figure методы Area() и ShowName() не содержат кода реализации (тела метода)?
Если в абстрактном классе метод объявлен как абстрактный (с ключевым словом abstract ), то этот метод не должен содержать реализации (согласно синтаксису Java). Это поясняется тем, что вызов этого метода не имеет смысла.
5.4. Можно ли в абстрактном классе Figure добавлять другие не абстрактные методы?
Да, можно. Абстрактный класс может содержать не абстрактные методы (в отличие от интерфейса ).
Нет, нельзя. То есть, следующая строка
есть ошибкой компилятора Java: «Cannot instantiate the type Figure».
Метод GetArea() получает ссылку с именем f абстрактного класса Figure, который есть базовым в иерархии классов (из класса Figure унаследованы два класса Triangle и Circle).
Затем по ссылке вызывается метод Area() в строке
В функции main() при вызове метода GetArea()
Точно таким же способом связывается экземпляр f2 класса Circle с обобщенной ссылкой f в методе GetArea()
6. Можно ли в абстрактном классе объявлять методы, которые имеют реализацию (тело)?
Да, можно. Абстрактный класс допускает реализацию не абстрактных методов.
7. Пример создания иерархии абстрактных классов
Пример. Ниже приведен пример иерархии абстрактных классов
Использование класса C может быть, например следующим
8. Может ли абстрактный класс не содержать абстрактных методов?
Да, может. Это необходимо в случаях, когда абстрактные методы в классе не нужны, но нужно запретить создание экземпляров этого класса.
9. Какие отличия между использованием абстрактных классов и использованием интерфейсов?
Между абстрактными классами и интерфейсами существуют следующие отличия:
10. Преимущества использования абстрактных классов
Использование абстрактных классов дает следующие преимущества:
ООП. Часть 6. Абстрактные классы и интерфейсы
Узнайте истинную мощь наследования и полиморфизма! Раскрываем секреты абстрактных классов и интерфейсов.
В предыдущей статье мы увидели, насколько удобнее становится ООП благодаря наследованию. Но оно может стать ещё лучше, если использовать абстрактные классы и интерфейсы.
Все статьи про ООП
Пишет о программировании, в свободное время создает игры. Мечтает открыть свою студию и выпускать ламповые RPG.
Абстрактные классы
Особенность абстрактных классов в том, что их можно использовать только как родительский класс, то есть вы не можете создать объект. Для их объявления используется ключевое слово abstract.
Это может понадобиться, чтобы объединить реализацию других схожих классов. Например, в вашей игре должны быть персонаж игрока и NPC (неигровые персонажи). У них могут быть общие свойства (имя, координаты) и методы (перемещение, изменение анимации).
Чтобы не повторять код несколько раз, можно вынести реализацию этих свойств и методов в абстрактный класс Character:
Тут всё как у обычных классов, но в конце можно заметить объявление свойства и метода без реализации. Реализация этих абстрактных свойств должна находиться в дочернем классе:
Когда объявляется реализация такого члена класса, необходимо указать ключевое слово override. Абстрактными могут быть следующие члены класса:
Дочерний класс должен реализовывать все члены родительского абстрактного класса, кроме тех случаев, когда дочерний класс тоже абстрактный.
В остальном всё очень похоже на обычные классы. Например, поле Y класса Character публичное, чтобы можно было использовать его в свойстве Y дочерних классов.
Абстрактный класс должен быть публичным.










