stringtranslate.com

Переопределение метода

Иллюстрация

Переопределение метода в объектно-ориентированном программировании — это функция языка, которая позволяет подклассу или дочернему классу предоставлять конкретную реализацию метода , который уже предоставлен одним из его суперклассов или родительских классов. Помимо предоставления управляемых данными параметров, определяемых алгоритмом, через виртуальные сетевые интерфейсы, [1] он также позволяет использовать определенный тип полиморфизма ( подтипирование ). Реализация в подклассе переопределяет (заменяет) реализацию в суперклассе, предоставляя метод с тем же именем, теми же параметрами или сигнатурой и тем же типом возвращаемого значения, что и метод в родительском классе. [2] Версия выполняемого метода будет определяться объектом , который используется для его вызова. Если для вызова метода используется объект родительского класса, то будет выполнена версия в родительском классе, но если для вызова метода используется объект подкласса, тогда будет выполнена версия в дочернем классе. [3] Это помогает предотвратить проблемы, связанные с аналитикой дифференциальных реле, которая в противном случае полагалась бы на структуру, в которой можно было бы избежать переопределения метода. [4] [5] Некоторые языки позволяют программисту предотвратить переопределение метода.

Примеры для конкретного языка

Ада

По умолчанию Ada предоставляет переопределение методов. Чтобы способствовать раннему обнаружению ошибок (например, орфографических ошибок), можно указать, когда метод будет фактически переопределяться, а когда нет. Это будет проверено компилятором.

 тип  Т  новый Управляется  с помощью ......; процедура Op ( Obj : in out T ; Данные : in Integer );          тип  NT   новый  T  с  нулевой записью ;  overriding   процедура переопределения индикатора  Op ( Obj : in  out  NT ;  Data : in  Integer );  overriding   процедура переопределения индикатора  Op ( Obj : in  out  NT ;  Data : in  String );  -- ^ компилятор выдает ошибку: подпрограмма "Op" не переопределяет

С#

C# поддерживает переопределение метода, но только если это явно запрошено с использованием модификаторов overrideи virtualили abstract.

абстрактный класс Animal { public string Name { get ; набор ; } // Методы public void Drink (); общественная виртуальная пустота Eat (); общественная пустота Go (); }                    класс Cat : Animal { public new string Name { get ; набор ; } // Методы public void Drink (); // Внимание: скрывает унаследованный напиток(). Использовать новое общедоступное переопределение void Eat (); // Переопределяет унаследованный метод eat(). общественный новый недействительный Go (); // Скрывает унаследованный go(). }                          

При переопределении одного метода другим сигнатуры двух методов должны быть идентичными (и с одинаковой видимостью). В C# методы классов , индексаторы , свойства и события могут быть переопределены.

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

Помимо модификаторов, используемых для переопределения метода, C# позволяет скрывать унаследованное свойство или метод. Это делается с использованием той же сигнатуры свойства или метода, но с добавлением модификатора newперед ней. [6]

В приведенном выше примере скрытие приводит к следующему:

Кот кот = новый Кот ();    кот . Имя = ; // обращается к Cat.Name cat . Есть (); // вызывает Cat.Eat() cat . Идти (); // вызывает Cat.Go() (( Animal ) cat ). Имя = ; // обращается к Animal.Name! (( Животное ) кот ). Есть (); // вызывает Cat.Eat()! (( Животное ) кот ). Идти (); // вызывает Animal.Go()!          

С++

В C++ нет ключевого слова super, которое подкласс может использовать в Java для вызова версии суперкласса метода, который он хочет переопределить. Вместо этого используется имя родительского или базового класса, за которым следует оператор разрешения области . Например, следующий код представляет два класса : базовый класс Rectangleи производный класс Box. Boxпереопределяет метод Rectangleкласса Print, чтобы также напечатать его высоту. [7]

#include <iostream> //------------------------------------------------ --------------------------- class Rectangle { public : Rectangle ( double l , double w ) : length_ ( l ), width_ ( w ) {} виртуальная пустота Print () const ;                частный : двойная длина_ ; двойная ширина_ ; };    //------------------------------------------------ --------------------------- void Rectangle::Print () const { // Метод печати базового класса. std :: cout << "Длина = " << длина_ << "; Ширина = " << ширина_ ; }             //------------------------------------------------ --------------------------- 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 { // Вызов родительского метода печати. Прямоугольник :: Печать (); std :: cout << "; Height = " << height_ ; }          

Метод Printв классе Box, вызывая родительскую версию метода Print, также может выводить частные переменные length и widthбазового класса. В противном случае эти переменные недоступны для Box.

Следующие операторы будут создавать экземпляры объектов типа Rectangleи Boxи вызывать их соответствующие Printметоды:

int main ( int argc , char ** argv ) { Прямоугольник ( 5.0 , 3.0 ) ;         // Выходы: Длина = 5.0; Ширина = 3,0 прямоугольника . Распечатать ();  Коробка ( 6.0 , 5.0 , 4.0 ) ;    // Указатель на самый переопределенный метод в vtable в Box::print, // но этот вызов не иллюстрирует переопределение. коробка . Распечатать ();   // Этот вызов иллюстрирует переопределение. // выходные данные: Длина = 6.0; Ширина = 5,0; Высота = 4,0 static_cast < Прямоугольник &> ( коробка ). Распечатать (); }  

В C++11 , как и в Java, метод, объявленный finalв суперклассе, не может быть переопределен; Кроме того, можно объявить метод override, чтобы компилятор проверил, переопределяет ли он метод базового класса.

Дельфи

В Delphi переопределение метода выполняется с помощью директивы override , но только в том случае, если метод был помечен динамическими или виртуальными директивами .

Унаследованное зарезервированное слово должно вызываться, когда вы хотите вызвать поведение суперкласса .

тип TRectangle = частный класс FLength : Double ; FWidth : Двойной ; общедоступное свойство Длина чтения FLength write FLength ; свойство Width чтение FWidth запись FWidth ;                      процедура Печать ; виртуальный ; конец ;    TBox = класс ( TRectangle ) общедоступная процедура Print ; переопределить ; конец ;       

Эйфелева

В Eiffel переопределение функции аналогично переопределению метода в C++ и Java. Переопределение — это одна из трех форм адаптации функций, классифицируемых как переобъявление . Повторное объявление также охватывает effecting , при котором предоставляется реализация функции, которая была отложена (абстрактной) в родительском классе, и undefinition , при которой функция, которая была эффективной (конкретной) в родительском классе, снова становится отложенной в классе-наследнике. Когда функция переопределяется, имя функции сохраняется в классе-наследнике, но свойства функции, такие как ее подпись, контракт (с учетом ограничений для предусловий и постусловий ) и/или реализация, будут отличаться в наследнике. Если исходная функция в родительском классе, называемая предшественником функции-наследника , эффективна, то будет эффективна и переопределенная функция в наследнике. Если предшественник откладывается, функция наследника будет отложена. [8]

Намерение переопределить функцию, как messageв примере ниже, должно быть явно объявлено в inheritпредложении класса-наследника.

сообщение функции класса THOUGHT - Отображение мыслительного сообщения do print ( "Я чувствую, что припаркован по диагонали в параллельной вселенной.%N" ) end end       class ADVICE inherit THOUGHT redefine message end Feature message -- Precursor do print ( "Предупреждение: даты в календаре ближе, чем кажутся.%N" ) end end           

В классе ADVICEфункция messageполучает реализацию, отличную от реализации ее предшественника в классе THOUGHT.

Рассмотрим класс, который использует экземпляры для обоих THOUGHTи ADVICE:

class APPLICATION create make Feature make -- Запустить приложение. сделать ( создать { МЫСЛЬ }). сообщение ; ( создать { СОВЕТ }). конец сообщения конец           

При создании экземпляра класс APPLICATIONвыдает следующий результат:

У меня такое ощущение, будто я припарковался по диагонали в параллельной вселенной. Внимание: Даты в календаре ближе, чем кажутся.

В пределах переопределенной функции доступ к ее предшественнику можно получить с помощью ключевого слова языка Precursor. Предположим, что реализация изменена следующим образом:{ADVICE}.message

 message -- Precursor do print ( "Предупреждение: даты в календаре ближе, чем кажутся.%N" ) Конец предшественника      

Вызов этой функции теперь включает в себя выполнение и выдает следующий результат:{THOUGHT}.message

Внимание: Даты в календаре ближе, чем кажутся. У меня такое ощущение, будто я припарковался по диагонали в параллельной вселенной.

Джава

В Java , когда подкласс содержит метод с той же сигнатурой (имя и типы параметров), что и метод в его суперклассе, тогда метод подкласса переопределяет метод суперкласса. Например:

класс  Мысль { общественное недействительное сообщение () { System . вне . println ( "Я чувствую себя так, будто нахожусь по диагонали в параллельной вселенной." ); } }       public class Advice расширяет Мысль { @Override // Аннотация @Override в Java 5 необязательна, но полезна. общественное недействительное сообщение () { System . вне . println ( "Внимание: даты в календаре ближе, чем кажутся." ); } }             

Класс Thoughtпредставляет суперкласс и реализует вызов метода . Вызванный подкласс наследует каждый метод, который может быть в классе. Класс переопределяет метод , заменяя его функциональность из .message()AdviceThoughtAdvicemessage()Thought

Мысль парковка = новая мысль (); парковка . сообщение (); // Выводит «У меня такое ощущение, будто я припарковался по диагонали в параллельной вселенной».     Даты мысли = новый совет (); // Даты полиморфизма . сообщение (); // Печатает «Внимание: даты в календаре ближе, чем кажутся».      

Когда подкласс содержит метод, который переопределяет метод суперкласса, то этот переопределенный метод (суперкласса) может быть явно вызван из метода подкласса с помощью ключевого слова super . [3] (Его нельзя явно вызвать из какого-либо метода, принадлежащего классу, не связанному с суперклассом.) Ссылка superможет быть

совет общественного класса расширяет мысль { @Override public void message () { System . вне . println ( "Внимание: даты в календаре ближе, чем кажутся." ); супер . сообщение (); // Вызов родительской версии метода. }              

Существуют методы, которые подкласс не может переопределить. Например, в Java метод, объявленный как Final в суперклассе, не может быть переопределен. Методы, объявленные частными или статическими, также не могут быть переопределены, поскольку они неявно являются окончательными. Класс, объявленный как Final, также не может стать суперклассом. [9]

Котлин

В Kotlin мы можем просто переопределить такую ​​функцию (обратите внимание, что функция должна быть open):

fun main () { val p = Родитель ( 5 ) val c = Дочерний ( 6 ) p . myFun () c . myFun () }            открытый класс Parent ( val a : Int ) { open fun myFun () = println ( a ) }           class Child ( val b : Int ) : Parent ( b ) { переопределить fun myFun () = println ( «переопределенный метод» ) }            

Питон

В Python , когда подкласс содержит метод, который переопределяет метод суперкласса, вы также можете вызвать метод суперкласса, вызвав [10] вместо . Пример:super(Subclass, self).methodself.method

class  Thought :  def  __init__ ( self )  ->  None :  print ( «Я новый объект типа Thought!» )  def  message ( self )  ->  None :  print ( «Я чувствую себя так, словно припаркован по диагонали в параллельной вселенной ." )класс  Совет ( Мысль ):  def  __init__ ( self )  ->  Нет :  супер ( Совет ,  self ) . __init__ ()  def  message ( self )  ->  None :  print ( «Внимание: даты в календаре ближе, чем кажутся» )  super ( Совет ,  self ) . сообщение ()t  =  Мысль () # "Я новый объект типа Мысль!" т . message () # «У меня такое ощущение, будто я припаркован по диагонали в параллельной вселенной.a  =  Advice () # "Я новый объект типа Мысль!" а . message () # "Внимание: даты в календаре ближе, чем кажутся" # "У меня такое ощущение, будто я припаркован по диагонали в параллельной вселенной.# ------------------ # Самоанализ:isinstance ( t ,  Thought ) # Правдаisinstance ( a ,  Совет ) # Верноisinstance ( a ,  Thought ) # Правда

Рубин

В Ruby , когда подкласс содержит метод, который переопределяет метод суперкласса, вы также можете вызвать метод суперкласса, вызвав super в этом переопределенном методе. Вы можете использовать псевдоним, если хотите, чтобы переопределенный метод был доступен за пределами переопределяющего метода, как показано в «super_message» ниже.

Пример:

Сообщение class Thought def гласит : «Я чувствую, что нахожусь по диагонали в параллельной вселенной». конец конец      class Advice < Псевдоним мысли :super_message :message def message помещает «Предупреждение: даты в календаре ближе, чем кажутся» super end end            

Примечания

  1. ^ Чжан, Цзе (2015). «Новый переопределенный API P2P для открытой передачи данных в WWW». Международная конференция IEEE по бытовой электронике, 2015 г., Тайвань . стр. 156–157. doi : 10.1109/ICCE-TW.2015.7216830. ISBN 978-1-4799-8745-0. S2CID  23295793.
  2. ^ Фланаган 2002, с. 107
  3. ^ ab Lewis & Loftus 2006, стр.454
  4. ^ Оверби, Дж (2011). «Дифференциальная проверка предварительных условий: легкий, многоразовый анализ для инструментов рефакторинга». 2011 26-я Международная конференция IEEE/ACM по автоматизированной разработке программного обеспечения (ASE 2011) . стр. 303–312. дои : 10.1109/ASE.2011.6100067. ISBN 978-1-4577-1639-3. S2CID  5933208.
  5. ^ Ли, К. (2014). «Остаточное расследование: прогнозируемое и точное обнаружение ошибок». Транзакции ACM по программной инженерии и методологии . 24 (2). дои : 10.1145/2656201. S2CID  47112802.
  6. ^ Мессенбёк, Ханспетер (25 марта 2002 г.). «Продвинутый C#: переопределение методов» (PDF) . Институт системного программного обеспечения, Университет Иоганна Кеплера в Линце, Факультет информатики. стр. 6–8 . Проверено 2 августа 2011 г.
  7. ^ Малик 2006, с. 676
  8. ^ Мейер 2009, стр. 572-575.
  9. ^ Дейтель и Дейтель 2001, стр.474.
  10. ^ в Python 3 - см. https://docs.python.org/3/library/functions.html#super. Архивировано 26 октября 2018 г. на Wayback Machine.super().method

Смотрите также

Рекомендации

Внешние ссылки