Override c что такое

от admin

Override C: что это за модификатор и как он используется в разработке?

Когда вы начнете изучать объектно-ориентированное программирование и в частности языки С или С++, то вы непременно столкнетесь с вопросом: override C — что это такое?

Ove r ride в языке программирования C является специальным типом идентификатора, который указывает на переопределение методов. Переопределение методов — это очень удобный и нужный механизм. Его смысл заключается в том, что вы создаете собственный дочерний метод в производственном классе, который повторяет какой-нибудь родительский метод, но со своей спецификацией. То есть перераспределение дает возможность изменять родительский класс до нужной нам функциональности. А при желании метод базового класса может быть и вовсе полностью переписан.

Что значит override в языке C

  • virtual — оповещает систему о необходимости переопределения метода;

  • override — показывает, что после этого слова идет переопределенный метод.

  1. Показать читателю кода, что после этого слова идет переопределенный виртуальный метод.

  2. Показать компилятору, что переопределенный метод — это не новый метод, а усовершенствованный старый.

Что это такое — override в языке C на примере

Приведем простейший пример для понимания работы этого слова-идентификатора.

Итак, допустим , у вас есть некий объект obj, у которого есть функция void hello():

class obj <

virtual void hello(); // Code : printf(«Привет!»);

>

Также у вас есть дочерний объект obj с функцией hello():

class bar : obj <

// no functions in here but yet, you can call

// bar.hello()

>

В этом случа е вы можете вывести : «Привет, мир!», когда функция hello() будет вызываться из объекта bar. Осуществить это можно переопределением метода:

class bar : obj <

virtual void hello() override; // Code : printf(«Привет, мир!»);

>

Выводы

  • идентификатор override в языке С показывает, что после него используется измененный переопределенный дочерний метод;

  • если хотите использовать override, то родительский метод обязательно должен быть помечен словом virtual.

Мы будем очень благодарны

если под понравившемся материалом Вы нажмёте одну из кнопок социальных сетей и поделитесь с друзьями.

Override c что такое

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

Те методы и свойства, которые мы хотим сделать доступными для переопределения, в базовом классе помечается модификатором virtual . Такие методы и свойства называют виртуальными.

А чтобы переопределить метод в классе-наследнике, этот метод определяется с модификатором override . Переопределенный метод в классе-наследнике должен иметь тот же набор параметров, что и виртуальный метод в базовом классе.

Например, рассмотрим следующие классы:

Здесь класс Person представляет человека. Класс Employee наследуется от Person и представляет сотруднника предприятия. Этот класс кроме унаследованного свойства Name имеет еще одно свойство — Company.

Чтобы сделать метод Print доступным для переопределения, этот метод определен с модификатором virtual . Поэтому мы можем переопределить этот метод, но можем и не переопределять. Допустим, нас устраивает реализация метода из базового класса. В этом случае объекты Employee будут использовать реализацию метода Print из класса Person:

Но также можем переопределить виртуальный метод. Для этого в классе-наследнике определяется метод с модификатором override , который имеет то же самое имя и набор параметров:

Возьмем те же самые объекты:

Виртуальные методы базового класса определяют интерфейс всей иерархии, то есть в любом производном классе, который не является прямым наследником от базового класса, можно переопределить виртуальные методы. Например, мы можем определить класс Manager, который будет производным от Employee, и в нем также переопределить метод Print.

При переопределении виртуальных методов следует учитывать ряд ограничений:

Виртуальный и переопределенный методы должны иметь один и тот же модификатор доступа. То есть если виртуальный метод определен с помощью модификатора public, то и переопредленный метод также должен иметь модификатор public.

Нельзя переопределить или объявить виртуальным статический метод.

Ключевое слово base

Кроме конструкторов, мы можем обратиться с помощью ключевого слова base к другим членам базового класса. В нашем случае вызов base.Print(); будет обращением к методу Print() в классе Person:

Переопределение свойств

Также как и методы, можно переопределять свойства:

В данном случае в классе Person определено виртуальное свойство Age, которое устанавливает значение, если оно больше 0 и меньше 110. В классе Employee это свойство переопределено — возраст работника должен быть не меньше 18.

Запрет переопределения методов

Также можно запретить переопределение методов и свойств. В этом случае их надо объявлять с модификатором sealed :

При создании методов с модификатором sealed надо учитывать, что sealed применяется в паре с override, то есть только в переопределяемых методах.

И в этом случае мы не сможем переопределить метод Print в классе, унаследованном от Employee.

Зачем нужно ключевое слово override

Есть 2 класса. Class2 содержит публичный виртуальный метод:

Class1 наследуется от Class2 и переписывает fun

Если создать объект Class1 и вызвать fun

на консоль будет выведено 1 и 2. Однако если удалить override и оставить :

то на консоль опять же выведет 1 и 2. Вопрос: зачем нужно ключевое слово override которое никак не влияет на результат? Понятно, что по идеи мы переписываем виртуальные методы внутри тел методов наследников, но для этого достаточно в базовом классе написать virtual , а в наследнике создать одноименный метод и вызвать base . Так получается, что слово override не нужно?

Real KEK's user avatar

Сергей's user avatar

Ключевое слово override нужно не компилятору (он-то прекрасно может увидеть, что метод базового класса виртуальный), а нам с вами, чтобы предотвратить ошибки.

Смотрите, пусть у нас была пара из виртуального метода и его переопределения, и мы переименовали виртуальный метод, а переименовать переопределение забыли. Или мы поменяли сигнатуру базового метода, а при смене сигнатуры переопределённого метода допустили ошибку в порядке аргументов. Или просто имплементируем виртуальный метод, но сделали ошибку в сигнатуре.

Если бы ключевое слово override не требовалось, компилятор прекрасно проглотил бы этот код: ну базовый метод виртуальный, а новый метод его не переопределяет, а просто определяет параллельный метод. А вот с ключевым словом override компилятор может поднять тревогу: override не перекрывает никакой метод, это явная ошибка.

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

Читать:
Как собрать проект c

Как отмечает @Алексей Шиманский в комментариях, если опустить ключевое слово override в вашем примере, то функция Class1.fun будут перекрывать по имени, но не виртуально переопределять функцию базового класса Class2.fun (и компилятор пожалуется, что вы не указали ключевое слово new , которое означает, что вы так делаете сознательно, а не по ошибке). Для вызова по точному типу объекта разницы нет, но разница будет, если вызывать по ссылке на базовый тип:

В этом случае Class2.fun и Class1.fun — несвязанные функции, и несмотря на virtual у Class2.fun , будет вызвана лишь функция базового класса.

Смысл виртуальных функций в том и состоит, что по ссылке на базовый класс будет вызвана реализация виртуальной функции из производного класса. (Вы можете не знать точный тип объекта во время выполнения.)

Введение в ООП с примерами на C#. Часть третья. Практические аспекты использования полиморфизма

Раньше в этой серии мы говорили о полиморфизме и наследовании.

В этой статье мы опять будем говорить о полиморфизме, но в этот раз сосредоточимся именно на практических нюансах, а не на теории. Если вы овладеете технологией, описанной в этой статье, то считайте, что изучили 50% ООП.

Ключевые слова New и Override в C#

Для начала создадим новое консольное приложение и два класса в нём:

Мы видим, что эти классы содержат три метода с попарно одинаковыми именами. Теперь выполним следующий код из Program.cs :

Жмём F5, т.е. выполняем код, и что мы видим?

ClassA AAA
ClassA BBB
ClassA CCC

ClassB AAA
ClassB BBB
ClassB CCC

ClassA AAA
ClassA BBB
ClassA CCC

Но кроме вывода, мы получили ещё и три предупреждения от компилятора:

‘InheritanceAndPolymorphism.ClassB.AAA()’ hides inherited member
‘InheritanceAndPolymorphism.ClassA.AAA()’. Use the new keyword if hiding was intended.

‘InheritanceAndPolymorphism.ClassB.BBB()’ hides inherited member
‘InheritanceAndPolymorphism.ClassA.BBB()’. Use the new keyword if hiding was intended.

‘InheritanceAndPolymorphism.ClassB.CCC()’ hides inherited member
‘InheritanceAndPolymorphism.ClassA.CCC()’. Use the new keyword if hiding was intended.

Что нужно запомнить: мы можем записать в переменную класса-родителя объект наследника, но не наоборот.

ClassA — родитель ClassB . То есть ClassB содержит то, что находится в ClassA и ещё что-то своё. В этом причина правила, которое мы записали выше: класс-родитель не содержит описания всех необходимых полей и методов класса-наследника, поэтому мы не можем использовать ClassA как ClassB .

Теперь посмотрим, что у нас происходит в коде. С x и y всё понятно: они объявлены и инициализированны одним и тем же типом. Рассмотрим подробнее z . Эта переменная типа ClassB , а её значение — объект типа ClassA , хотя в данном контексте нет никакой разницы, какого типа её значение, вывод всегда будет аналогичен выводу от y . Выбор метода по типу ссылки, а не по типу объекта — это стандартное поведение, когда явно не указан приоритет методов, о чём свидетельствуют warning’и. Как же описать требуемое поведение? Здесь нам как раз помогут ключевые слова new и override .

Давайте проведём эксперимент

Добавим к двум методам из ClassB ключевые слова new и override следующим образом:

Если мы сейчас выполним Program.cs , то на выходе получим:

Error: ‘InheritanceAndPolymorphism.ClassB.AAA()’: cannot override inherited member
‘InheritanceAndPolymorphism.ClassA.AAA()’ because it is not marked virtual, abstract, or override

Ошибка возникает из-за того, что поля родителя не помечены ключевым словом virtual . Этот модификатор обозначает, что мы имеем право вызывать метод из дочернего класса или перезаписывать его. Добавим virtual ко всем методам ClassA :

И снова запустим Program.cs :

ClassB AAA
ClassB BBB
ClassB CCC

ClassA AAA
ClassA BBB
ClassA CCC

ClassB AAA
ClassA BBB
ClassA CCC

Очевидно, что метод дочернего класса вызвался только там, где стоял модификатор override . В свзяи с чем делаем вывод: override значит, что помеченный метод — новая версия родительского и должен использоваться вместо него. И, напротив, new обозначает, что метод, хоть и случайно имеет такое же имя, является по сути абсолютно другим, а значит, в нашем примере должен выполняться метод родительского класса. Если мы не пишем никакого модификатора, мы подразумеваем именно new .
Разберём подробнее логику C#. Когда вызывается метод какого-то объекта по ссылке, то в первую очередь он смотрит на тип ссылки. Если в этом классе обнаружен модификатор virtual , он начинает искать среди дочерних классов тип объекта, и, если встречает new , запускает последний override метод, который встретил (либо метод типа ссылки). Возможно, это не слишком понятно, обратимся к более сложному примеру.

Эксперимент с тремя классами

Результатом такого эксперимента станет:

ClassA AAA
ClassA BBB
ClassB CCC

ClassA AAA
ClassA BBB
ClassB CCC

ClassC AAA
ClassB BBB
ClassB CCC

В первом случае мы имеем дело с типом ссылки ClassA и типом объекта ClassB . Компилятор действует вполне очевидно:

Во втором случае тип объекта у нас уже ClassC . Поскольку он наследуется от ClassA не напрямую, а через ClassB , наша диаграмма будет уже несколько сложнее.

В третьем случае мы имеем дело снова с двумя классами, ClassA мы просто игнорируем. Если учесть это, то вывод будет очевиден, но всё же вот схема:

Важным замечанием будет, что следующий код:

Error: ‘InheritanceAndPolymorphism.C.X()’: cannot override inherited member
‘InheritanceAndPolymorphism.B.X()’ because it is not marked virtual, abstract, or override

Ведь из-за того, что в B метод помечен как new , он не наследует свойство virtual , а значит не может быть перезаписан с помощью override в C . Правильным вариантом было бы добавить к описанию метода в B ключевое слово virtual или изменить в C override на new , в зависимости от требуемого поведения.

Ключевое слово base

Теперь, когда мы разобрались с самой сложной частью, стоит напомнить про возможность вызова методов родительского класса из дочернего. Простой пример:

ClassA XXX
ClassB XXX

ClassA XXX
ClassB XXX
ClassC XXX

В первом случае выполняется метод ClassB , который через base вызывает метод из ClassA . Во втором — XXX() из ClassC , который обращается к ClassB , а тот, в свою очередь, к ClassA .

Похожие статьи