Перегрузка функций
![]() | В этой статье есть несколько проблем. Пожалуйста, помогите улучшить его или обсудите эти проблемы на странице обсуждения . ( Узнайте, как и когда удалять эти шаблонные сообщения )
|
Полиморфизм |
---|
Специальный полиморфизм |
Параметрический полиморфизм |
Подтипирование |
В некоторых языках программирования перегрузка функций или перегрузка методов — это возможность создавать несколько функций с одинаковым именем и разными реализациями. Вызовы перегруженной функции будут запускать конкретную реализацию этой функции, соответствующую контексту вызова, позволяя одному вызову функции выполнять различные задачи в зависимости от контекста.
Например, доТаск() и doTask(object o) — это перегруженные функции. Чтобы вызвать последний, объект должен быть передан в качестве параметра , тогда как первый не требует параметра и вызывается с пустым полем параметра. Распространенной ошибкой было бы присвоение значения по умолчанию объекту во второй функции, что привело бы к неоднозначной ошибке вызова , поскольку компилятор не знал бы, какой из двух методов использовать.
Другим примером является Функция Print(object o) , выполняющая различные действия в зависимости от того, печатается ли текст или фотографии. Две разные функции могут быть перегружены как Печать (text_object T); Печать(изображение_объект P) . Если мы напишем перегруженные функции печати для всех объектов, которые наша программа будет «печатать», нам никогда не придется беспокоиться о типе объекта и правильном вызове функции, вызов всегда будет: Распечатать (что-то) .
Языки, поддерживающие перегрузку [ править ]
Языки, поддерживающие перегрузку функций, включают, помимо прочего, следующее:
- Апекс
- С++
- С#
- Кложур [1]
- Быстрый
- Фортран
- Котлин [2]
- Ява [3]
- Юлия
- PostgreSQL [4] и PL/SQL [5]
- Скала
- Машинопись
- Визуальный Бейсик (.NET)
- Вольфрам Язык
- Эликсир
- Nim [6]
- Кристалл [7]
- Дельфи [8]
Правила перегрузки функций [ править ]
- Одно и то же имя функции используется для более чем одного определения функции.
- Функции должны различаться либо арностью , либо типами параметров.
Это классификация статического полиморфизма, в которой вызов функции разрешается с использованием некоторого алгоритма «наилучшего соответствия», где конкретная вызываемая функция разрешается путем нахождения наилучшего соответствия типов формальных параметров фактическим типам параметров. Детали этого алгоритма варьируются от языка к языку.
Перегрузка функций обычно связана со статически типизированными языками программирования, которые обеспечивают проверку типов при вызовах функций . Перегруженная функция на самом деле представляет собой просто набор различных функций, имеющих одно и то же имя. Для каждого конкретного вызова компилятор определяет, какую перегруженную функцию использовать, и решает это во время компиляции . Это справедливо для таких языков программирования, как Java. [9]
В Java перегрузка функций также известна как полиморфизм времени компиляции и статический полиморфизм.
Перегрузку функций не следует путать с формами полиморфизма , где выбор делается во время выполнения, например, с помощью виртуальных функций , а не статически.
Пример: перегрузка функции в C++
#include <iostream>
int Volume(int s) { // Volume of a cube.
return s * s * s;
}
double Volume(double r, int h) { // Volume of a cylinder.
return 3.1415926 * r * r * static_cast<double>(h);
}
long Volume(long l, int b, int h) { // Volume of a cuboid.
return l * b * h;
}
int main() {
std::cout << Volume(10);
std::cout << Volume(2.5, 8);
std::cout << Volume(100l, 75, 15);
}
В приведенном выше примере объем каждого компонента рассчитывается с использованием одной из трех функций под названием «объем», выбор которых основан на различном количестве и типе фактических параметров.
Перегрузка конструктора [ править ]
Конструкторы , используемые для создания экземпляров объекта, также могут быть перегружены в некоторых объектно-ориентированных языках программирования . Поскольку во многих языках имя конструктора предопределено именем класса, может показаться, что конструктор может быть только один. Всякий раз, когда требуется несколько конструкторов, их следует реализовать как перегруженные функции. В C++ конструкторы по умолчанию объекта не принимают никаких параметров, создавая экземпляры членов с соответствующими значениями по умолчанию, «которые обычно равны нулю для числовых полей и пустой строке для строковых полей». [10] Например, конструктор по умолчанию для объекта счета в ресторане, написанного на C++, может установить чаевые равными 15 %:
Bill()
: tip(0.15), // percentage
total(0.0)
{ }
Недостаток этого подхода в том, что для изменения значения созданного объекта Bill требуется два шага. Ниже показано создание и изменение значений в основной программе:
Bill cafe;
cafe.tip = 0.10;
cafe.total = 4.00;
Перегрузив конструктор, можно было передать подсказку и сумму в качестве параметров при создании. Это показывает перегруженный конструктор с двумя параметрами. Этот перегруженный конструктор размещается в классе так же, как и исходный конструктор, который мы использовали ранее. Какой из них будет использоваться, зависит от количества параметров, предоставленных при создании нового объекта Bill (ни одного или два):
Bill(double tip, double total)
: tip(tip),
total(total)
{ }
Теперь функция, создающая новый объект Bill, может передавать в конструктор два значения и устанавливать элементы данных за один шаг. Ниже показано создание и установка значений:
Bill cafe(0.10, 4.00);
Это может быть полезно для повышения эффективности программы и уменьшения длины кода.
Другой причиной перегрузки конструктора может быть принудительное применение обязательных элементов данных. В этом случае конструктор по умолчанию объявляется закрытым или защищенным (или предпочтительно удаленным, начиная с C++11 ), чтобы сделать его недоступным извне. Для приведенного выше счета итоговая сумма может быть единственным параметром конструктора, поскольку у счета нет разумного значения по умолчанию для общей суммы, тогда как значение по умолчанию составляет 0,15.
Осложнения [ править ]
Две проблемы взаимодействуют и усложняют перегрузку функций: маскирование имени (из-за области видимости ) и неявное преобразование типов .
Если функция объявлена в одной области, а затем другая функция с тем же именем объявлена во внутренней области, существует два естественных возможных варианта поведения перегрузки: внутреннее объявление маскирует внешнее объявление (независимо от сигнатуры) или оба внутренних объявления и внешнее объявление включены в перегрузку, причем внутреннее объявление маскирует внешнее объявление только в том случае, если подпись совпадает. Первое взято из C++: «в C++ нет перегрузки между областями видимости». [11] В результате, чтобы получить набор перегрузок с функциями, объявленными в разных областях видимости, необходимо явно импортировать функции из внешней области во внутреннюю, с помощью using
ключевое слово.
Неявное преобразование типов усложняет перегрузку функций, поскольку, если типы параметров не совсем совпадают с сигнатурой одной из перегруженных функций, но могут совпадать после преобразования типов, разрешение зависит от того, какое преобразование типа выбрано.
Они могут сочетаться запутанным образом: например, неточное совпадение, объявленное во внутренней области, может маскировать точное совпадение, объявленное во внешней области. [11]
Например, чтобы иметь производный класс с перегруженной функцией, принимающей double
или int
, используя функцию, принимающую int
из базового класса на C++ можно было бы написать:
class B {
public:
void F(int i);
};
class D : public B {
public:
using B::F;
void F(double d);
};
Не удалось включить using
приводит к int
параметр, переданный в F
в производном классе преобразуется в двойной и соответствует функции в производном классе, а не в базовом классе; Включая using
приводит к перегрузке производного класса и, таким образом, соответствует функции базового класса.
Предостережения [ править ]
Если метод разработан с чрезмерным количеством перегрузок, разработчикам может быть сложно определить, какая перегрузка вызывается, просто прочитав код. Это особенно верно, если некоторые из перегруженных параметров имеют типы, унаследованные от других возможных параметров (например, «объект»). IDE может выполнить разрешение перегрузки и отобразить (или перейти к) правильную перегрузку.
Перегрузка на основе типов также может затруднить обслуживание кода, поскольку обновления кода могут случайно изменить перегрузку метода, выбранную компилятором. [12]
См. также [ править ]
- Абстракция (информатика)
- Конструктор (информатика)
- Аргумент по умолчанию
- Динамическая отправка
- Шаблон фабричного метода
- Сигнатура метода
- Переопределение метода
- Объектно-ориентированное программирование
- Перегрузка оператора
Цитаты [ править ]
- ^ «Clojure — Изучите Clojure — Функции» . Clojure.org . Проверено 13 июня 2023 г.
- ^ «Спецификация языка Котлин» . kotlinlang.org .
- ^ Блох 2018 , с. 238-244, §Глава 8 Пункт 52: Удалить непроверенные предупреждения.
- ^ «37.6. Перегрузка функций» . Документация PostgreSQL . 12 августа 2021 г. Проверено 29 августа 2021 г.
- ^ «Руководство и справочник пользователя по базам данных PL/SQL» . docs.oracle.com . Проверено 29 августа 2021 г.
- ^ «Руководство Нима» . nim-lang.org .
- ^ «Кристалл Документы» . Crystal-lang.org .
- ^ «Эмбаркадеро Дельфы» . embarcadero.com .
- ^ Блох 2018 , с. 238-244, §Глава 8, пункт 52: Используйте перегрузку разумно.
- ^ Чан, Джейми (2017). Изучите C# за один день и выучите его хорошо (пересмотренная ред.). п. 82. ИСБН 978-1518800276 .
- ^ Jump up to: Перейти обратно: а б Страуструп, Бьерн . «Почему перегрузка не работает для производных классов?» .
- ^ Браха, Гилад (3 сентября 2009 г.). «Системная перегрузка» . Комната 101.
Ссылки [ править ]
- Блох, Джошуа (2018). «Эффективная Java: Руководство по языку программирования» (третье изд.). Аддисон-Уэсли. ISBN 978-0134685991 .
Внешние ссылки [ править ]
- Мейер, Бертран (октябрь 2001 г.). «Перегрузка против объектной технологии» (PDF) . Эйфелева колонна. Журнал объектно-ориентированного программирования . 14 (4). ООО «101 Коммуникации»: 3–7 . Проверено 27 августа 2020 г.