Jump to content

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

Иллюстрация

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

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

[ редактировать ]

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

  type T is new Controlled with ......;
  procedure Op(Obj: in out T; Data: in Integer);

  type NT is new T with null record;
  overriding    -- overriding indicator
  procedure Op(Obj: in out NT; Data: in Integer);
  overriding    -- overriding indicator
  procedure Op(Obj: in out NT; Data: in String);
  -- ^ compiler issues an error: subprogram "Op" is not overriding

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

abstract class Animal
{
    public          string Name { get; set; }
    // Methods
    public          void   Drink();
    public virtual  void   Eat();
    public          void   Go();
}

class Cat : Animal
{
    public new      string Name { get; set; }
    // Methods
    public          void   Drink();  // Warning: hides inherited drink(). Use new
    public override void   Eat();    // Overrides inherited eat().
    public new      void   Go();     // Hides inherited go().
}

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

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

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

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

Cat cat = new Cat();

cat.Name = ;             // accesses Cat.Name
cat.Eat();                // calls Cat.Eat()
cat.Go();                 // calls Cat.Go()
((Animal)cat).Name = ;   // accesses Animal.Name!
((Animal)cat).Eat();      // calls Cat.Eat()!
((Animal)cat).Go();       // calls 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) {}
  virtual void Print() const;

 private:
  double length_;
  double width_;
};

//---------------------------------------------------------------------------
void Rectangle::Print() const {
  // Print method of base class.
  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;

 private:
  double height_;
};

//---------------------------------------------------------------------------
// Print method of derived class.
void Box::Print() const {
  // Invoke parent Print method.
  Rectangle::Print();
  std::cout << "; Height = " << height_;
}

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

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

int main(int argc, char** argv) {
  Rectangle rectangle(5.0, 3.0);

  // Outputs: Length = 5.0; Width = 3.0
  rectangle.Print();

  Box box(6.0, 5.0, 4.0);

  // The pointer to the most overridden method in the vtable in on Box::print,
  // but this call does not illustrate overriding.
  box.Print();

  // This call illustrates overriding.
  // outputs: Length = 6.0; Width = 5.0; Height= 4.0
  static_cast<Rectangle&>(box).Print();
}

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

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

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

type
  TRectangle = class
  private
    FLength: Double;
    FWidth: Double;
  public
    property Length read FLength write FLength;
    property Width read FWidth write FWidth;

    procedure Print; virtual;
  end;

  TBox = class(TRectangle)
  public
    procedure Print; override;
  end;

Эйфелева

[ редактировать ]

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

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

class
    THOUGHT
feature
    message
            -- Display thought message
        do
            print ("I feel like I am diagonally parked in a parallel universe.%N")
        end
end

class
    ADVICE
inherit
    THOUGHT
        redefine
            message
        end
feature
    message
            -- Precursor
        do
            print ("Warning: Dates in calendar are closer than they appear.%N")
        end
end

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

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

class
    APPLICATION
create
    make
feature 
    make
            -- Run application.
        do
            (create {THOUGHT}).message;
            (create {ADVICE}).message
        end
end

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

I feel like I am diagonally parked in a parallel universe.
Warning: Dates in calendar are closer than they appear.

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

    message
            -- Precursor
        do
            print ("Warning: Dates in calendar are closer than they appear.%N")
            Precursor
        end

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

Warning: Dates in calendar are closer than they appear.
I feel like I am diagonally parked in a parallel universe.

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

class Thought {
    public void message() {
        System.out.println("I feel like I am diagonally parked in a parallel universe.");
    }
}

public class Advice extends Thought {
    @Override  // @Override annotation in Java 5 is optional but helpful.
    public void message() {
        System.out.println("Warning: Dates in calendar are closer than they appear.");
    }
}

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

Thought parking = new Thought();
parking.message();  // Prints "I feel like I am diagonally parked in a parallel universe."

Thought dates = new Advice();  // Polymorphism
dates.message();  // Prints "Warning: Dates in calendar are closer than they appear."

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

public class Advice extends Thought {
      @Override
      public void message() {
          System.out.println("Warning: Dates in calendar are closer than they appear.");
          super.message();  // Invoke parent's version of method.
      }

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

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

fun main() {
    val p = Parent(5)
    val c = Child(6)
    p.myFun()
    c.myFun()
}

open class Parent(val a : Int) {
    open fun myFun() = println(a)
}

class Child(val b : Int) : Parent(b) {
    override fun myFun() = println("overrided method")
}

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

class Thought:
    def __init__(self) -> None:
        print("I'm a new object of type Thought!")
    def message(self) -> None:
        print("I feel like I am diagonally parked in a parallel universe.")

class Advice(Thought):
    def __init__(self) -> None:
        super(Advice, self).__init__()
    def message(self) -> None:
        print("Warning: Dates in calendar are closer than they appear")
        super(Advice, self).message()

t = Thought()
# "I'm a new object of type Thought!"
t.message()
# "I feel like I am diagonally parked in a parallel universe.

a = Advice()
# "I'm a new object of type Thought!"
a.message()
# "Warning: Dates in calendar are closer than they appear"
# "I feel like I am diagonally parked in a parallel universe.

# ------------------
# Introspection:

isinstance(t, Thought)
# True

isinstance(a, Advice)
# True

isinstance(a, Thought)
# True

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

Пример:

class Thought
  def message
    puts "I feel like I am diagonally parked in a parallel universe."
  end
end

class Advice < Thought
  alias :super_message :message
  def message
    puts "Warning: Dates in calendar are closer than they appear"
    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. ^ Jump up to: а б Льюис и Лофтус 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. ^ super().method в Python 3 - см. https://docs.python.org/3/library/functions.html#super. Архивировано 26 октября 2018 г. на Wayback Machine.

См. также

[ редактировать ]
  • Дейтель, Х.М. и Дейтель, П.Дж. (2001). Как программировать на Java (4-е изд.). Река Аппер-Седл, Нью-Джерси: Прентис-Холл.
  • Льюис Дж. и Лофтус В. (2008). Java: программные решения (6-е изд.). Бостон, Массачусетс: Пирсон Аддисон Уэсли.
  • Малик, Д.С. (2006). Программирование на C++: разработка программ, включая структуру данных. (3-е изд.). Вашингтон, округ Колумбия: Курс технологии.
  • Фланаган, Дэвид. (2002). Коротко о Java. Получено с http://oreilly.com/catalog/9780596002831/preview#preview.
  • Мейер, Бертран (2009). Прикосновение к классу: учимся хорошо программировать с объектами и контрактами . Спрингер.
[ редактировать ]
Arc.Ask3.Ru: конец переведенного документа.
Arc.Ask3.Ru
Номер скриншота №: 0a0583edb350cf5ff206109ae9b87401__1720144140
URL1:https://arc.ask3.ru/arc/aa/0a/01/0a0583edb350cf5ff206109ae9b87401.html
Заголовок, (Title) документа по адресу, URL1:
Method overriding - Wikipedia
Данный printscreen веб страницы (снимок веб страницы, скриншот веб страницы), визуально-программная копия документа расположенного по адресу URL1 и сохраненная в файл, имеет: квалифицированную, усовершенствованную (подтверждены: метки времени, валидность сертификата), открепленную ЭЦП (приложена к данному файлу), что может быть использовано для подтверждения содержания и факта существования документа в этот момент времени. Права на данный скриншот принадлежат администрации Ask3.ru, использование в качестве доказательства только с письменного разрешения правообладателя скриншота. Администрация Ask3.ru не несет ответственности за информацию размещенную на данном скриншоте. Права на прочие зарегистрированные элементы любого права, изображенные на снимках принадлежат их владельцам. Качество перевода предоставляется как есть. Любые претензии, иски не могут быть предъявлены. Если вы не согласны с любым пунктом перечисленным выше, вы не можете использовать данный сайт и информация размещенную на нем (сайте/странице), немедленно покиньте данный сайт. В случае нарушения любого пункта перечисленного выше, штраф 55! (Пятьдесят пять факториал, Денежную единицу (имеющую самостоятельную стоимость) можете выбрать самостоятельно, выплаичвается товарами в течение 7 дней с момента нарушения.)