stringtranslate.com

Перегрузка функций

В некоторых языках программирования перегрузка функций или перегрузка методов — это возможность создавать несколько функций с одним и тем же именем с разными реализациями. Вызовы перегруженной функции будут запускать конкретную реализацию этой функции, соответствующую контексту вызова, позволяя одному вызову функции выполнять разные задачи в зависимости от контекста.

Например, doTask() и doTask(object o) являются перегруженными функциями. Чтобы вызвать последний, объект должен быть передан в качестве параметра , тогда как первый не требует параметра и вызывается с пустым полем параметра. Распространенной ошибкой было бы присвоение значения по умолчанию объекту во второй функции, что привело бы к неоднозначной ошибке вызова , поскольку компилятор не знал бы, какой из двух методов использовать.

Другой пример — функция Print(object o) , которая выполняет различные действия в зависимости от того, печатает ли она текст или фотографии. Две разные функции могут быть перегружены как Print(text_object T); Печать(изображение_объект P) . Если мы напишем перегруженные функции печати для всех объектов, которые наша программа будет «печатать», нам никогда не придется беспокоиться о типе объекта и повторном правильном вызове функции, вызов всегда будет: Print(something) .

Языки, поддерживающие перегрузку

Языки, поддерживающие перегрузку функций, включают, помимо прочего, следующее:

Правила перегрузки функций

Это классификация статического полиморфизма, в которой вызов функции разрешается с использованием некоторого алгоритма «наилучшего соответствия», где конкретная вызываемая функция разрешается путем нахождения наилучшего соответствия типов формальных параметров фактическим типам параметров. Детали этого алгоритма варьируются от языка к языку.

Перегрузка функций обычно связана со статически типизированными языками программирования, которые обеспечивают проверку типов при вызовах функций . Перегруженная функция на самом деле представляет собой просто набор различных функций, имеющих одно и то же имя. Для каждого конкретного вызова компилятор определяет, какую перегруженную функцию использовать, и решает это во время компиляции . Это справедливо для таких языков программирования, как Java. [8]

В Java перегрузка функций также известна как полиморфизм времени компиляции и статический полиморфизм.

Перегрузку функций не следует путать с формами полиморфизма , где выбор делается во время выполнения, например, с помощью виртуальных функций , а не статически.

Пример: перегрузка функции в C++

#include <iostream> int Volume ( int s ) { // Объем куба. вернуть с * с * с ; }          double Volume ( double r , int h ) { // Объем цилиндра. return 3.1415926 * r * r * static_cast <double> ( h ) ; _ }              long Volume ( long l , int b , int h ) { // Объем кубоида. вернуть л * б * ч ; }              int main () { std :: cout << Volume ( 10 ); std :: cout << Volume ( 2.5 , 8 ); std :: cout << Объем ( 100л , 75 , 15 ); }              

В приведенном выше примере объем каждого компонента рассчитывается с использованием одной из трех функций под названием «объем», выбор которых основан на различном количестве и типе фактических параметров.

Перегрузка конструктора

Конструкторы , используемые для создания экземпляров объекта, также могут быть перегружены в некоторых объектно-ориентированных языках программирования . Поскольку во многих языках имя конструктора предопределено именем класса, может показаться, что конструктор может быть только один. Всякий раз, когда требуется несколько конструкторов, их следует реализовать как перегруженные функции. В C++ конструкторы по умолчанию не принимают никаких параметров, создавая экземпляры членов объекта с соответствующими значениями по умолчанию, «которые обычно равны нулю для числовых полей и пустой строке для строковых полей». [9] Например, конструктор по умолчанию для объекта счета в ресторане, написанный на C++, может установить размер чаевых равным 15 %:

Bill () : чаевые ( 0,15 ), // общая сумма в процентах ( 0,0 ) { }     

Недостаток этого подхода в том, что для изменения значения созданного объекта Bill требуется два шага. Ниже показано создание и изменение значений в основной программе:

Билл кафе ; кафе . чаевые = 0,10 ; кафе . итого = 4,00 ;     

Перегрузив конструктор, можно было передать подсказку и сумму в качестве параметров при создании. Это показывает перегруженный конструктор с двумя параметрами. Этот перегруженный конструктор размещается в классе так же, как и исходный конструктор, который мы использовали ранее. Какой из них будет использоваться, зависит от количества параметров, предоставленных при создании нового объекта Bill (ни одного или два):

Счет ( двойные чаевые , двойная сумма ) : чаевые ( чаевые ), общая сумма ( всего ) { }       

Теперь функция, создающая новый объект Bill, может передавать в конструктор два значения и устанавливать элементы данных за один шаг. Ниже показано создание и установка значений:

Билл- кафе ( 0.10 , 4.00 );  

Это может быть полезно для повышения эффективности программы и уменьшения длины кода.

Другой причиной перегрузки конструктора может быть принудительное применение обязательных элементов данных. В этом случае конструктор по умолчанию объявляется закрытым или защищенным (или предпочтительно удаленным, начиная с C++11 ), чтобы сделать его недоступным извне. Для приведенного выше счета итоговая сумма может быть единственным параметром конструктора, поскольку у счета нет разумного значения по умолчанию для общей суммы, тогда как значение по умолчанию составляет 0,15.

Осложнения

Две проблемы взаимодействуют и усложняют перегрузку функций: маскирование имени (из-за области видимости ) и неявное преобразование типов .

Если функция объявлена ​​в одной области, а затем другая функция с тем же именем объявлена ​​во внутренней области, существует два естественных возможных варианта поведения перегрузки: внутреннее объявление маскирует внешнее объявление (независимо от сигнатуры) или оба внутренних объявления и внешнее объявление включены в перегрузку, причем внутреннее объявление маскирует внешнее объявление только в том случае, если подпись совпадает. Первое взято из C++: «в C++ нет перегрузки между областями действия». [10] В результате, чтобы получить набор перегрузок с функциями, объявленными в разных областях видимости, необходимо явно импортировать функции из внешней области видимости во внутреннюю область видимости с помощью ключевого слова using.

Неявное преобразование типов усложняет перегрузку функций, поскольку, если типы параметров не совсем совпадают с сигнатурой одной из перегруженных функций, но могут совпадать после преобразования типов, разрешение зависит от того, какое преобразование типа выбрано.

Они могут сочетаться запутанным образом: например, неточное совпадение, объявленное во внутренней области, может маскировать точное совпадение, объявленное во внешней области. [10]

Например, чтобы иметь производный класс с перегруженной функцией, принимающей a doubleили an int, используя функцию, принимающую a intиз базового класса, в C++ можно было бы написать:

класс B { public : void F ( int i ); };      класс D : public B { public : using B :: F ; пустота F ( двойной d ); };           

Невозможность включить usingрезультаты в intпараметр, переданный Fв производный класс, который преобразуется в двойное значение и соответствует функции в производном классе, а не в базовом классе; Включение usingприводит к перегрузке производного класса и, таким образом, соответствует функции базового класса.

Предостережения

Если метод разработан с чрезмерным количеством перегрузок, разработчикам может быть сложно определить, какая перегрузка вызывается, просто прочитав код. Это особенно верно, если некоторые из перегруженных параметров имеют типы, унаследованные от других возможных параметров (например, «объект»). IDE может выполнить разрешение перегрузки и отобразить (или перейти к) правильную перегрузку.

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

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

Цитаты

  1. ^ "Clojure - Изучите Clojure - Функции" . Clojure.org . Проверено 13 июня 2023 г.
  2. ^ «Спецификация языка Kotlin» . kotlinlang.org .
  3. ^ Блох 2018, с. 238-244, §Глава 8 Пункт 52: Удалить непроверенные предупреждения.
  4. ^ «37.6. Перегрузка функций». Документация PostgreSQL . 12 августа 2021 г. Проверено 29 августа 2021 г.
  5. ^ «Руководство и справочник пользователя по базе данных PL/SQL» . docs.oracle.com . Проверено 29 августа 2021 г.
  6. ^ "Руководство Нима" . nim-lang.org .
  7. ^ "Кристалл Документы". Crystal-lang.org .
  8. ^ Блох 2018, с. 238-244, §Глава 8, пункт 52: Используйте перегрузку разумно.
  9. ^ Чан, Джейми (2017). Изучите C# за один день и выучите его хорошо (пересмотренная ред.). п. 82. ИСБН 978-1518800276.
  10. ^ аб Страуструп, Бьярн . «Почему не работает перегрузка для производных классов?».
  11. Браха, Гилад (3 сентября 2009 г.). «Системная перегрузка». Комната 101.

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

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