Переопределение метода - Method overriding
Переопределение метода в объектно-ориентированном программировании - это языковая функция, которая позволяет подклассу или дочернему классу предоставлять конкретную реализацию метода, который уже предоставлен одним из его суперклассов или родительских классов. Он допускает определенный тип полиморфизма ( подтипы ). Реализация в подклассе переопределяет (заменяет) реализацию в суперклассе, предоставляя метод с тем же именем, такими же параметрами или сигнатурой и тем же возвращаемым типом, что и метод в родительском классе. Версия выполняемого метода будет определяться объектом, который используется для его вызова. Если для вызова метода используется объект родительского класса, то будет выполнена версия в родительском классе, но если для вызова метода используется объект подкласса, то будет выполнена версия в дочернем классе. Некоторые языки позволяют программисту предотвратить переопределение метода.
Примеры для конкретных языков
Ада
Ада по умолчанию обеспечивает переопределение метода. Чтобы способствовать раннему обнаружению ошибок (например, орфографической ошибки), можно указать, когда метод, как ожидается, будет фактически заменять или нет. Это будет проверено компилятором.
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 #
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
перед ним.
В приведенном выше примере скрытие вызывает следующее:
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 ++
В C ++ нет ключевого слова, которое подкласс может использовать в Java для вызова версии суперкласса метода, который он хочет переопределить. Вместо этого используется имя родительского или базового класса, за которым следует оператор разрешения области видимости . Например, следующий код представляет два класса : базовый класс и производный класс . переопределяет метод класса , чтобы также напечатать его высоту.
super
Rectangle
Box
Box
Rectangle
Print
#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
В Delphi переопределение метода выполняется с помощью переопределения директивы , но только в том случае, если метод был отмечен динамическими или виртуальными директивами.
Унаследовали зарезервированное слово должно быть названо , когда вы хотите назвать супер-класс поведения
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. Переопределение - это одна из трех форм адаптации функций, классифицируемых как переопределение . Переопределение также охватывает осуществления , в котором реализация предусмотрена функция , которая была отсроченной (реферат) в родительском классе, и undefinition , в котором особенность , которая была эффективной (бетон) в родительском становится отложено снова в классе наследника. Когда функция переопределяется, имя функции сохраняется за классом-наследником, но свойства функции, такие как подпись, контракт (с учетом ограничений для предусловий и постусловий ) и / или реализация, будут отличаться у наследника. Если исходный объект в родительском классе, называемый предшественником объекта-наследника , действует, то будет действовать переопределенный объект в наследнике. Если предшественник отложен, функция наследника будет отложена.
Намерение переопределить функцию, как 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.
В переопределенной функции доступ к предшественнику функции можно получить с помощью ключевого слова language 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 , когда подкласс содержит метод, который переопределяет метод суперкласса, он также может вызвать метод суперкласса с помощью ключевого слова super
. Пример:
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
Ссылка может быть
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, стал суперклассом.
Котлин
В 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
В Python , когда подкласс содержит метод, который переопределяет метод суперкласса, вы также можете вызвать метод суперкласса, вызвав вместо . Пример:
super(Subclass, self).method
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
Примечания
Смотрите также
- Наследование реализации
- Семантика наследования
- Перегрузка метода
- Полиморфизм в объектно-ориентированном программировании
- Шаблон метода шаблона
- Виртуальное наследование
- 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). Прикосновение класса: научиться хорошо программировать с объектами и контрактами . Springer.
внешние ссылки
- Переопределение метода Java от Хеманта Баладжи
- Введение в концепции ООП и многое другое от Nirosh LwC
- Методы переопределения и сокрытия с помощью Sun Microsystems