logo-01-01
C++ Лекция Виртуальные Функции И Полиморфизм
СодержаниеОбращение К Базовому КлассуВиртуальные ФункцииЧистая Виртуальная ФункцияВиртуальные Функции Что Это Такое? Часть 2Абстрактные Классы И Чистые Виртуальные ФункцииВиртуальные Функции И Их Переопределение Во всех производных классах описана собственная замещающая виртуальная функция speak(), которая печатает на экран, какие же звуки издает конкретное животное. В качестве базового класса мы соорудили абстрактный класс Animal. Он имеет единственный член-данные […]

Во всех производных классах описана собственная замещающая виртуальная функция speak(), которая печатает на экран, какие же звуки издает конкретное животное. В качестве базового класса мы соорудили абстрактный класс Animal. Он имеет единственный член-данные Title, описывающий кличку животного. В нем есть явно определенный конструктор, который присваивает животному его «имя». И единственная чистая виртуальная функция speak(), которая описывает, какие звуки издает животное.

Как уже говорилось, невозможно создать объект абстрактного класса. Абстрактный класс нельзя применять для задания типа параметра функции, или в качестве типа возвращаемого значения. Зато можно определять ссылки и указатели на абстрактные классы. Ключевым моментом в использовании виртуальной функции для обеспечения полиморфизма времени исполнения служит то, что используется указатель именно на базовый класс. Полимор­физм времени исполнения достигается только при вызове виртуальной функции с использовани­ем указателя или ссылки на базовый класс. Однако ничто не мешает вызывать виртуальные функ­ции, как и любые другие «нормальные» функции, однако достичь полиморфизма времени исполнения на этом пути не удается.

Виртуальная функция вызывается только через указатель или ссылку на базовый класс. Virtual используется в базовом классе, чтобы сделать функцию виртуальной (полиморфной). https://globalcloudteam.com/ru/ Можно подумать, что все остальные функции «грязные»! Чистая – в данном случае означает буквально пустая функция. Давайте посмотрим, что такое чистая виртуальная функция.

Обращение К Базовому Классу

Когда мы объявляем функцию виртуальной, используя virtual, то это равносильно тому, как если бы мы обращались к ней не напрямую, а через указатель. Везде написано, что он указывает на то что, метод переопределен, но в примерах его никто не использует, а в исходниках я его встречаю строго постоянно. В следующей части мы попытаемся рассмотреть несколько более сложный момент. Посмотрим, что такое виртуальные деструкторы классов, зачем они нужны, и как с ними бороться. Рассмотрение теории виртуальных функций в общем случае мы закончили. Для упрощения примера ограничимся в описании каждого животного его кличкой и типовым издаваемым животным звуком.

  • Кроме override существует спецификатор final, который запрещает переопределение виртуальной функции в классах-потомках.
  • Ну, например, ближе к ночи лев захотел спать, и стал зевать.
  • Virtual используется в базовом классе, чтобы сделать функцию виртуальной (полиморфной).
  • Поскольку р указывает на объект типа first_d, то ис­пользуется соответствующая версия функции who().

Следует отметить тот факт, что закрытый виртуальный метод базового класса нельзя вызвать из наследника, но без проблем можно переопределить. Для иерархии типа полезно иметь абстрактный базовый класс. Он содержит общие свойства иерархии типа, но каждый порожденный класс реализует эти свойства по-своему. — это функция, которая определяется в базовом классе, а любой порожденный класс может ее переопределить.

Виртуальные Функции

В данном случае функция display представляет совершенно новую реализацию, которая не имеет ничего общего с базовым классом Person. Она скрывает по сути виртуальную функцию из базового класса. Теперь функция display может быть переопределена в производных классах. Причем производный класс может и не переопределять функцию, а использовать унаследованный функционал. Виртуальная функция отличается об обычной функции тем, что для обычной функции связывание вызова функции с ее определением осуществляется на этапе компиляции. Для виртуальных функций это происходит во время выполнения программы.

Что означает virtual C++

После создания объекта указатель на эту vtable, называемый виртуальный табличный указатель или vpointer, добавляется как скрытый член данного объекта (а зачастую как первый член). Компилятор также генерирует «скрытый» код в конструкторе каждого класса для инициализации vpointer-ов виртуальные функции на С++ его объектов адресами соответствующей vtable. Координирующая таблица объекта содержит адреса динамически связанных методов объекта. Метод вызывается при выборке адреса метода из таблицы. По сравнению с обычными классами, абстрактные классы пользуются «ограниченными правами».

Но это не так, и термин перегрузка функции не приме­ним к переопределению виртуальной функции, поскольку между ними имеются существенные раз­личия. Во-первых, функция должна соответствовать прототипу. Как известно, при перегрузке обычной функции число и тип параметров должны быть различными. Однако при переопределе­нии виртуальной функции интерфейс функции должен в точности соответствовать прототипу.

Чистая Виртуальная Функция

Для разных объектов вызываются разные версии одной и той же виртуальной функции. Класс, содержащий одну или более вир­туальных функций, называется полиморфным классом . Эта программа выводит на экран те же самые данные, что и предыдущая версия. В данном при­мере функция show_who() имеет параметр типа ссылки на класс Base. В функции main() вызов виртуальной функции осуществляется с использованием объектов типа Base, first_d и second_d.

Аналогично, когда указателю р присвоен адрес объекта second_obj, то используется версия функции who(), объявленная в классе second_d. Надо иметь в виду, что характеристики наследования носят иерархический характер. Чтобы проиллюстрировать это, предположим, что в предыдущем примере класс second_d порожден от класса first_d вместо класса Base. В общем случае, когда класс не переопределяет виртуальную функцию, С++ использует первое из определений, которое он находит, идя от потомков к предкам. На первый взгляд переопределение виртуальной функции в производном классе выглядит как специальная форма перегрузки функции.

В силу различий между перегрузкой обычных функций и переопределением виртуальных фун­кций будем использовать для последних термин переопределение . Для рассмотренного выше примера (класс Фигура) функцию вычисления площади целесообразно задать чистой виртуальной функцией, которую переопределяет каждый наследуемый класс. Реализация функции зависит от класса и будет различной в каждом порожденном классе.

После этого объявлен указатель р на класс Base, затем объекты first_obj и second_obj, относящиеся к двум производным классам. Далее указателю р при­своен адрес объекта base_objи вызвана функция who(). В данном случае им является объект типа Base, поэтому исполняется версия функции who(), объявленная в классе Base. Затем указате­лю р присвоен адрес объекта first_obj. Поскольку р указывает на объект типа first_d, то ис­пользуется соответствующая версия функции who().

Виртуальные Функции Что Это Такое? Часть 2

Кстати, не смотря на всю его простоту, он вполне может быть основой для создания простейшей развивающей игры для детей «очень младшего возраста».

Что означает virtual C++

Если же такого соответствия нет, то такая функция просто рассматривается как перегруженная и она утрачивает свои виртуальные свойства. Кроме того, если отличается только тип возвращаемо­го значения, то выдается сообщение об ошибке. Тем не менее виртуальная функция может быть другом другого класса. Хотя деструктор может быть виртуальным, но конструктор виртуальным быть не может. Полиморфизм времени исполнения обеспечивается за счет использования производных классов и виртуальных функций. Виртуальная функция — это функция, объявленная с ключевым словом virtual в базовом классе и переопределенная в одном или в нескольких производных классах.

Однако функция display в классе Person выводит еще и возраст человека. Но поскольку переменная age в классе Person определена как закрытая, то класс Employee не имеет к ней доступа. Виртуальная функция объявляется в базовом классе с использованием ключевого слова virtual. Когда же она переопределяется в производном классе, повторять ключевое слово virtual нет не­обходимости, хотя и в случае его повторного использования ошибки не возникнет. «A virtual function has the same argument types as one in a base class, but a different return type. This is illegal.» То есть – виртуальная функция имеет тот же аргумент, что и в базовом классе, но возвращает другой тип.

Ну, а основной (и увы, единственной) возможностью программы будет вывод на экран списка кличек животных и представления издаваемых ими звуков. Public-наследование позволяет установить между классами отношение ЯВЛЯЕТСЯ. Т.е., если класс B открыто унаследован от A, то объект класса B ЯВЛЯЕТСЯ объектом класса A, но не наоборот.

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

Абстрактные Классы И Чистые Виртуальные Функции

Вызываемая версия функции who() в функции show_who() определяется типом объекта, на кото­рый ссылается параметр при вызове функции. Это тот самый случай, когда объявляется замещающая виртуальная функция с тем же самым типом возвращаемого значения, но с другим набором параметров. Что в случае со звуками, которые издает лев может быть передано функции speak(), как параметр?

Виртуальные Функции И Их Переопределение

Как можно видеть, в объекте Base функция who() объявлена как виртуальная. Это означает, что эта функция может быть переопределена в производных классах. В каждом из классов first_d и second_d функция who() переопределена.

Кроме override существует спецификатор final, который запрещает переопределение виртуальной функции в классах-потомках. Как и всякий класс, абстрактный класс может иметь явно определенный конструктор. Но обращение из конструктора к чистым виртуальным функциям приведут к ошибкам во время выполнения программы. Однако, в строке 4 вызовется метод name базового класса Person, хотя по логике следовало бы тоже ожидать вызовname() класса Student — ведь p — это ссылка на объект производного класса. Теперь в классе Employee функция display выводит имя и компанию сотрудника.

Посмотрите другие вопросы с метками c++ c++11 или задайте свой вопрос. Возможность override появилась в С++ начиная с С++11. Ваши лекции и примеры в них были скорее всего изначально составлены еще до того времени и с тех пор не обновлялись. Допускается, но не рекомендуется использование virtual совместно с override. Возвращаясь к воинственному примеру из первой части, надо сказать, что в этом случае это абсолютно миролюбивый и даже «детский» пример.

Тогда как в классе Employee определена дополнительная переменная - company, которая хранит компанию, в которой работает объект Employee. И было бы хорошо, если бы для объекта Employee функция display также выводила бы значения переменной company. Обычно компилятор создает отдельную vtable для каждого класса.

Virtual И Override

Предположение типа «каким местом издается звук» я отмел сразу же и бесповоротно. Предположим, что это зависимость от времени суток, то есть «когда». Ну, например, ближе к ночи лев захотел спать, и стал зевать. Поэтому в данном случае функции speakпередан параметр When, который правда в ней нигде не используется, но это не важно.

Для каждого класса, содержащего виртуальные методы, или унаследованного от класса с виртуальными методами, создается таблица виртуальных функций. Эта таблица предназначена для вызова нужных реализаций виртуальных методов во время исполнения программы. При создании экземпляра класса, указатель на VFT этого класса помещается в самое начало созданного объекта. Производный класс может определить функцию с тем же именем, что и виртуальная функция в базовом классе, с тем же или другим списком параметров.

Для компилятора такая функция будет существовать независимо от базового класса. И подобное определение функции в производном классе не будет переопределением функции из базового класса. Указатель на базовый класс может указывать либо на объект базового класса, либо на объект порожденного класса. Выбор функции-члена зависит от того, на объект какого класса при выполнении программы указывает указатель, но не от типа указателя. При отсутствии члена порожденного класса по умолчанию используется виртуальная функция базового класса.

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *