Переопределение метода в объектно-ориентированном программировании - это языковая функция, которая позволяет подклассу или дочернему классу предоставлять конкретную реализацию метода, который уже предоставлен одним из его суперклассов или родительских классов. Реализация в подклассе переопределяет (заменяет) реализацию в суперклассе, предоставляя метод с тем же именем, такими же параметрами или сигнатурой и тем же возвращаемым типом, что и метод в родительском классе. [1] Версия выполняемого метода будет определяться объектомкоторый используется для его вызова. Если для вызова метода используется объект родительского класса, то будет выполнена версия в родительском классе, но если для вызова метода используется объект подкласса, то будет выполнена версия в дочернем классе. [2] Некоторые языки позволяют программисту предотвратить переопределение метода.
У него такая же подпись с тем же типом аргумента, который был переопределен в дочернем классе.
Примеры для конкретных языков [ править ]
Ада [ править ]
Ада по умолчанию обеспечивает переопределение метода. Чтобы способствовать раннему обнаружению ошибок (например, орфографической ошибки), можно указать, когда метод, как ожидается, будет фактически заменять или нет. Это будет проверено компилятором.
типа Т является новым Controlled с ......; процедура Op ( Obj : in out T ; Data : in Integer ); тип NT - новый T с нулевой записью ; overriding - переопределение индикаторной процедуры Op ( Obj : in out NT ; Data : in Integer ); overriding - переопределение индикаторной процедуры Op ( Obj : in out NT ; Data : in String ); - ^ компилятор выдает ошибку: подпрограмма "Op" не отменяет
C # [ править ]
C # поддерживает переопределение методов, но только в случае явного запроса с использованием модификаторов override
и virtual
или abstract
.
абстрактный класс Animal { общедоступная строка Имя { получить ; набор ; } // Методы public void Drink (); общедоступная виртуальная пустота Eat (); public void Go (); }class Cat : Animal { общедоступная новая строка Имя { получить ; набор ; } // Методы public void Drink (); // Предупреждение: скрывает унаследованный drink (). Использовать новое общедоступное переопределение void Eat (); // Переопределяет унаследованный eat (). общедоступный новый void Go (); // Скрывает унаследованный go (). }
При замене одного метода другим сигнатуры двух методов должны быть идентичными (и с одинаковой видимостью). В C # все методы класса , индексаторы , свойства и события могут быть переопределены.
Невиртуальные или статические методы нельзя переопределить. Переопределенный базовый метод должен быть виртуальным , абстрактным или переопределяемым .
В дополнение к модификаторам, которые используются для переопределения метода, C # позволяет скрыть унаследованное свойство или метод. Это делается с использованием той же сигнатуры свойства или метода, но с добавлением модификатора new
перед ним. [3]
В приведенном выше примере скрытие вызывает следующее:
Кот кот = новый Кот ();кот . Имя = … ; // обращается к Cat.Name cat . Ешьте (); // вызывает Cat.Eat () cat . Перейти (); // вызывает Cat.Go () (( Animal ) cat ). Имя = … ; // обращается к Animal.Name! (( Животное ) кошка ). Ешьте (); // вызывает Cat.Eat ()! (( Животное ) кошка ). Перейти (); // вызывает Animal.Go ()!
C ++ [ править ]
В C ++ нет ключевого слова, super
которое подкласс может использовать в Java для вызова версии суперкласса метода, который он хочет переопределить. Вместо этого используется имя родительского или базового класса, за которым следует оператор разрешения области видимости . Например, следующий код представляет два класса : базовый класс Rectangle
и производный класс Box
. Box
переопределяет метод Rectangle
класса Print
, чтобы также напечатать его высоту. [4]
#include <iostream>// ------------------------------------------------ --------------------------- class Rectangle { public : Rectangle ( double l , double w ) : length_ ( l ), width_ ( w ) {} виртуальная пустота Print () const ; частный : двойная длина_ ; двойная ширина_ ; };// ------------------------------------------------ --------------------------- void Rectangle :: Print () const { // Метод печати базового класса. std :: cout << "Length =" << length_ << "; Width =" << width_ ; }// ------------------------------------------------ --------------------------- class Box : public Rectangle { public : Box ( double l , double w , double h ) : Rectangle ( l , w ), height_ ( h ) {} void Print () const override ; частный : двойная высота_ ; };// ------------------------------------------------ --------------------------- // Печать метода производного класса. void Box :: Print () const { // Вызов родительского метода Print. Прямоугольник :: Печать (); std :: cout << "; Height =" << height_ ; }
Метод Print
в классе Box
, вызывая родительскую версию метода Print
, также может выводить частные переменные length
и width
базовый класс. В противном случае эти переменные недоступны для Box
.
Следующие операторы будут создавать экземпляры объектов типа Rectangle
и Box
и вызывать их соответствующие Print
методы:
int main ( int argc , char ** argv ) { Прямоугольник прямоугольник ( 5.0 , 3.0 ); // Вывод: Length = 5.0; Ширина = 3,0 прямоугольника . Печать (); Коробка коробка ( 6.0 , 5.0 , 4.0 ); // Указатель на наиболее переопределяемый метод в vtable в Box :: print, // но этот вызов не иллюстрирует переопределение. коробка . Печать (); // Этот вызов иллюстрирует переопределение. // выводит: Length = 6.0; Ширина = 5,0; Высота = 4.0 static_cast < Прямоугольник &> ( прямоугольник ). Печать (); }
В C ++ 11 , как и в Java, метод, объявленный final
в суперклассе, не может быть переопределен; Кроме того, можно объявить метод, override
чтобы компилятор проверял, переопределяет ли он метод в базовом классе.
Delphi [ править ]
В Delphi переопределение метода выполняется с помощью переопределения директивы , но только в том случае, если метод был отмечен динамическими или виртуальными директивами.
Унаследовали зарезервированное слово должно быть названо , когда вы хотите назвать супер-класс поведения
тип TRectangle = частный класс FLength : Double ; FWidth : двойной ; публичное свойство Длина чтения FLength write FLength ; свойство Ширина читать FWidth писать FWidth ; процедура Print ; виртуальный ; конец ; TBox = class ( TRectangle ) публичная процедура Print ; переопределить ; конец ;
Эйфель [ править ]
В Eiffel , функция переопределение аналогичен методу переопределяя в C ++ и Java. Переопределение - это одна из трех форм адаптации функций, классифицируемых как переопределение . Переопределение также охватывает осуществления , в котором реализация предусмотрена функция , которая была отсроченной (реферат) в родительском классе, и undefinition , в котором особенность , которая была эффективной (бетон) в родительском становится отложено снова в классе наследника. Когда функция переопределяется, имя функции сохраняется наследником класса, но свойства функции, такие как ее подпись, контракт (с учетом ограничений для предусловий и постусловий), и / или реализация будет отличаться в наследнике. Если исходный объект в родительском классе, называемый предшественником объекта-наследника , эффективен, то будет действовать переопределенный объект в наследнике. Если предшественник отложен, функция наследника будет отложена. [5]
Намерение переопределить функцию, как message
в примере ниже, должно быть явно объявлено в inherit
предложении класса-наследника.
сообщение функции class THOUGHT - Показать мысленное сообщение do print ( «Я чувствую, что припаркован по диагонали в параллельной вселенной.% N» ) конец конец class ADVICE наследовать THOUGHT переопределить сообщение end feature message - Предшественник do print ( «Предупреждение: даты в календаре ближе, чем они появляются.% N» ) end end
В классе ADVICE
функции message
предоставляется реализация, которая отличается от реализации ее предшественника в классе THOUGHT
.
Рассмотрим класс, который использует экземпляры для THOUGHT
и ADVICE
:
class APPLICATION create make feature make - Запустить приложение. делать ( создать { МЫСЛЬ }). сообщение ; ( создать { СОВЕТ }). конец сообщения конец
При APPLICATION
создании экземпляра класс выдает следующий результат:
Я чувствую себя припаркованным по диагонали в параллельной вселенной.Предупреждение: даты в календаре ближе, чем кажутся.
В переопределенной функции доступ к предшественнику функции можно получить с помощью ключевого слова language Precursor
. Предположим, что реализация изменена следующим образом:{ADVICE}.message
message - Preursor do print ( «Предупреждение: даты в календаре ближе, чем они кажутся.% N» ) Конец предшественника
Вызов функции теперь включает выполнение и дает следующий результат:{THOUGHT}.message
Предупреждение: даты в календаре ближе, чем кажутся.Я чувствую себя припаркованным по диагонали в параллельной вселенной.
Java [ править ]
В Java , когда подкласс содержит метод, который переопределяет метод суперкласса, он также может вызывать метод суперкласса с помощью ключевого слова super
. [2]
Пример:
class Thought { public void message () { System . из . println ( "Мне кажется, что я припаркован по диагонали в параллельной вселенной." ); } }открытый класс Advice расширяет Thought { @Override // Аннотация @Override в Java 5 не является обязательной, но полезной. public void message () { System . из . println ( "Предупреждение: даты в календаре ближе, чем кажутся." ); } }
Класс Thought
представляет суперкласс и реализует вызов метода . Вызываемый подкласс наследует все методы, которые могут быть в классе. Однако класс переопределяет метод , заменяя его функциональность из .message()
Advice
Thought
Advice
message()
Thought
Парковка мыслей = новая мысль (); парковка . сообщение (); // Печатает «Мне кажется, что я припаркован по диагонали в параллельной вселенной». Даты мысли = новый совет (); // Полиморфизм дат . сообщение (); // Выводит «Предупреждение: даты в календаре ближе, чем кажется».
super
Ссылка может быть
открытый класс Advice расширяет Thought { @Override public void message () { System . из . println ( "Предупреждение: даты в календаре ближе, чем кажутся." ); супер . сообщение (); // Вызов родительской версии метода. }
Есть методы, которые подкласс не может переопределить. Например, в Java метод, объявленный как final в суперклассе, не может быть переопределен. Методы, объявленные частными или статическими, нельзя переопределить, потому что они неявно являются окончательными. Также невозможно, чтобы класс, объявленный final, стал суперклассом. [6]
Котлин [ править ]
В Kotlin мы можем просто переопределить такую функцию: обратите внимание, что функция должна быть открытой.
весело main ( args : Array < String > ) { var t = test ( 5 ) var s = test2 ( 6 ) t . myFun () s . myFun () } тест открытого класса ( var a : Int ) { open fun myFun () = println ( a ) } class test2 ( var b : Int ) : test ( b ) { переопределить fun myFun () = println ( "переопределенный метод" ) }
Python [ править ]
В Python , когда подкласс содержит метод, который переопределяет метод суперкласса, вы также можете вызвать метод суперкласса, вызвав [7] вместо . Пример:super(Subclass, self).method
self.method
class Thought : def __init__ ( self ) -> None : print ( «Я новый объект типа Thought!» ) def message ( self ) -> None : print ( «Мне кажется, что я припаркован по диагонали в параллельной вселенной. . " )class Advice ( Мысль ): def __init__ ( self ) -> None : super ( Advice , self ) . __init__ () def message ( self ) -> None : print ( «Предупреждение: даты в календаре ближе, чем они кажутся» ) super ( Advice , self ) . сообщение ()t = Thought () # "Я новый объект типа Thought!" т . message () # "Мне кажется, что я припаркован по диагонали в параллельной вселенной.a = Advice () # "Я новый объект типа Мысль!" а . message () # "Предупреждение: даты в календаре ближе, чем кажется" # "Мне кажется, что я припаркован по диагонали в параллельной вселенной.# ------------------ # Самоанализ:isinstance ( t , Мысль ) # Истинаisinstance ( a , Совет ) # Trueisinstance ( a , Мысль ) # Истина
Руби [ править ]
В Ruby, когда подкласс содержит метод, который переопределяет метод суперкласса, вы также можете вызвать метод суперкласса, вызвав super в этом переопределенном методе. Вы можете использовать псевдоним, если хотите, чтобы переопределенный метод был доступен вне метода переопределения, как показано ниже с помощью «super_message».
Пример:
классового мысли DEF сообщение путы «Я чувствую, что я по диагонали припаркован в параллельной вселенной.» конец конецclass Advice < Псевдоним мысли : super_message : message def message помещает «Предупреждение: даты в календаре ближе, чем они кажутся» super end end
Заметки [ править ]
- Перейти ↑ Flanagan 2002, p. 107
- ^ a b Льюис и Лофтус 2006, стр.454
- ^ Mössenböck, Hanspeter (2002-03-25). «Расширенный C #: переопределение методов» (PDF) . http://ssw.jku.at/Teaching/Lectures/CSharp/Tutorial/ : Institut für Systemsoftware, Университет Йоханнеса Кеплера в Линце, Fachbereich Informatik. С. 6–8 . Проверено 2 августа 2011 .
- ^ Малик 2006, стр. 676
- ^ Мейер 2009, стр. 572-575
- ^ Дейтель & Дейтель 2001, p.474
- ^ в Python 3 - см. https://docs.python.org/3/library/functions.html#super Архивировано 26 октября 2018 г. на Wayback Machine
super().method
См. Также [ править ]
- Наследование реализации
- Семантика наследования
- Перегрузка метода
- Полиморфизм в объектно-ориентированном программировании
- Шаблон метода шаблона
- Виртуальное наследование
- HTTP-заголовок X-HTTP-Method-Override
Ссылки [ править ]
- Дейтель, Х. М. и Дейтель, П.Дж. (2001). Java, как программировать (4-е изд.). Река Аппер Сэдл, штат Нью-Джерси: Prentice Hall.
- Льюис, Дж. И Лофтус, В. (2008). Java: программные решения (6-е изд.). Бостон, Массачусетс: Пирсон Аддисон Уэсли.
- Малик, Д.С. (2006). Программирование на C ++: проектирование программ, включая структуру данных. (3-е изд.). Вашингтон, округ Колумбия: Технология курса.
- Фланаган, Дэвид. (2002). Java в двух словах. Получено с http://oreilly.com/catalog/9780596002831/preview#preview.
- Мейер, Бертран (2009). Touch of Class: Учимся хорошо программировать с объектами и контрактами . Springer.
Внешние ссылки [ править ]
- Переопределение метода Java от Хеманта Баладжи
- Введение в концепции ООП и многое другое от Nirosh LwC
- Методы переопределения и сокрытия с помощью Sun Microsystems