stringtranslate.com

Перегрузка оператора

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

Обоснование

Перегрузка операторов — это синтаксический сахар , и используется, поскольку позволяет программировать с использованием нотации, более близкой к целевой области [1], и предоставляет определяемым пользователем типам аналогичный уровень синтаксической поддержки, как и встроенным в язык типам. Это распространено, например, в научных вычислениях, где позволяет манипулировать вычислительными представлениями математических объектов с тем же синтаксисом, что и на бумаге.

Перегрузка операторов не изменяет выразительную силу языка (с функциями), поскольку ее можно эмулировать с помощью вызовов функций. Например, рассмотрим переменные a, bи cнекоторого определенного пользователем типа, например матрицы :

a + b * c

В языке, поддерживающем перегрузку операторов, и с обычным предположением, что оператор «*» имеет более высокий приоритет , чем оператор «+», это будет кратким способом записи:

Add(a, Multiply(b, c))

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

Примеры

В этом случае оператор сложения перегружается, чтобы разрешить сложение с пользовательским типом Timeв C++ :

Оператор времени + ( const Time & lhs , const Time & rhs ) { Время temp = lhs ; temp . seconds += rhs . seconds ; temp . minutes += temp . seconds / 60 ; temp . seconds %= 60 ; temp . minutes += rhs . minutes ; temp . hours += temp . minutes / 60 ; temp . minutes %= 60 ; temp . hours += rhs . hours ; return temp ; }                                      

Сложение — это бинарная операция , то есть у нее два операнда . В C++ передаваемые аргументы — это операнды, а tempобъект — это возвращаемое значение.

Операцию также можно определить как метод класса, заменив lhsего скрытым thisаргументом; Однако это заставит левый операнд иметь тип Time:

// "const" прямо перед открывающейся фигурной скобкой означает, что |this| не изменяется. Time Time :: Operator + ( const Time & rhs ) const { Time temp = * this ; // |this| не должен изменяться, поэтому создаем копию. temp . seconds += rhs . seconds ; temp . minutes += temp . seconds / 60 ; temp . seconds %= 60 ; temp . minutes += rhs . minutes ; temp . hours += temp . minutes / 60 ; temp . minutes %= 60 ; temp . hours += rhs . hours ; return temp ; }                                     

Обратите внимание, что унарный оператор, определенный как метод класса, не будет получать видимых аргументов (он работает только из this):

bool Время :: оператор ! () const { return часы == 0 && минуты == 0 && секунды == 0 ; }               

Оператор «меньше» (<) часто перегружается для сортировки структуры или класса:

класс Пара { public : bool оператор < ( const Пара & p ) const { if ( x_ == p . x_ ) { return y_ < p . y_ ; } return x_ < p . x_ ; }                         частный : int x_ ; int y_ ; };    

Как и в предыдущих примерах, в последнем примере перегрузка операторов выполняется внутри класса. В C++ после перегрузки оператора «меньше» (<) для сортировки некоторых классов можно использовать стандартные функции сортировки .

Критика

Перегрузка операторов часто подвергалась критике [2] , поскольку она позволяет программистам переназначать семантику операторов в зависимости от типов их операндов. Например, использование оператора <<в C++ сдвигает биты в переменной слева на биты, если и имеют целочисленный тип, но если является выходным потоком, то приведенный выше код попытается записать в поток. Поскольку перегрузка операторов позволяет исходному программисту изменять обычную семантику оператора и заставать врасплох последующих программистов, считается хорошей практикой использовать перегрузку операторов с осторожностью (создатели Java решили не использовать эту возможность, [3] хотя и не обязательно по этой причине).a << bababab

Другая, более тонкая проблема с операторами заключается в том, что некоторые правила из математики могут быть ошибочно ожидаемы или непреднамеренно приняты. Например, коммутативность + (т. е. что a + b == b + a) не всегда применима; пример этого возникает, когда операнды являются строками, так как + обычно перегружается для выполнения конкатенации строк (т. е. "bird" + "song"дает "birdsong", в то время "song" + "bird"как дает "songbird"). Типичный контраргумент [ требуется цитата ] к этому аргументу исходит непосредственно из математики: в то время как + является коммутативным для целых чисел (и, в более общем смысле, для любых комплексных чисел), он не является коммутативным для других «типов» переменных. На практике + даже не всегда ассоциативен , например, для значений с плавающей точкой из-за ошибок округления. Другой пример: в математике умножение является коммутативным для действительных и комплексных чисел, но не коммутативным при умножении матриц .

Каталог

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

Хронология перегрузки операторов

1960-е

Спецификация ALGOL 68 допускала перегрузку операторов. [44]

Выдержка из спецификации языка АЛГОЛ 68 (стр. 177), где определены перегруженные операторы ¬, =, ≠ и abs :

10.2.2 Операции над булевыми операндамиа) оп ∨ = ( логическое значение a, b) логическое значение :( a | истина | b );б) оп ∧ = ( bool a, b) bool : ( a | b | false );в) оп ¬ = ( bool a) bool : ( a | false | true );г) оп = = ( булев а, б) булев :( а∧б ) ∨ ( ¬б∧¬а );д) оп ≠ = ( логическое a, b) логическое : ¬(a=b);е) оп  abs = ( bool a) int : ( a | 1 | 0 );

Обратите внимание, что для перегрузки оператора не требуется специального объявления , и программист может свободно создавать новые операторы. Для диадических операторов можно задать их приоритет по сравнению с другими операторами:

 прио  макс = 9;  op  max = ( int a, b) int : ( a>b | a | b ); op  ++ = ( ref  int a ) int : ( a +:= 1 );

1980-е

Ada поддерживает перегрузку операторов с самого начала, с публикацией стандарта языка Ada 83. Однако разработчики языка решили исключить определение новых операторов. Только существующие операторы в языке могут быть перегружены путем определения новых функций с идентификаторами, такими как "+", "*", "&" и т. д. Последующие версии языка (в 1995 и 2005 годах) сохраняют ограничение на перегрузку существующих операторов.

В C++ перегрузка операторов более совершенна, чем в ALGOL 68. [ 45]

1990-е

Разработчики языка Java в Sun Microsystems решили отказаться от перегрузки. [46] [47] [48]

Python допускает перегрузку операторов посредством реализации методов со специальными именами. [49] Например, оператор сложения (+) можно перегрузить, реализовав метод obj.__add__(self, other).

Ruby допускает перегрузку операторов в качестве синтаксического сахара для простых вызовов методов.

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

2000-е

Microsoft добавила перегрузку операторов в C# в 2001 году и в Visual Basic .NET в 2003 году.

Scala рассматривает все операторы как методы и, таким образом, допускает перегрузку операторов через прокси.

В Raku определение всех операторов делегировано лексическим функциям, и поэтому, используя определения функций, операторы могут быть перегружены или добавлены новые операторы. Например, функция, определенная в исходном коде Rakudo для увеличения объекта Date с помощью "+", выглядит так:

мульти  инфикс:<+> ( Дата:D  $d , Целое:D  $x ) { Дата . новый-от-дня ( $d . день + $x )}

Поскольку было использовано "multi", функция добавляется в список кандидатов multidispatch , а "+" перегружается только в случае, когда выполняются ограничения типа в сигнатуре функции. Хотя возможности перегрузки включают + , * , >= , постфикс и термин i и т. д., она также позволяет перегружать различные операторы фигурных скобок: " [ x, y ] ", "x [ y ] ", "x { y } " и "x ( y ) ".

Kotlin поддерживает перегрузку операторов с момента своего создания.

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

Ссылки

  1. ^ Страуструп, Бьярне . "Перегрузка операторов". C++ FAQ . Архивировано из оригинала 14 августа 2011 г. Получено 27 августа 2020 г.
  2. ^ Фишер, Чарльз Н. (2008). «Проблемы перегрузки» (PDF) . Университет Висконсина–Мэдисона .
  3. ^ "Больше никакой перегрузки операторов". Языковая среда Java . Корпорация Oracle .
  4. ^ Могут быть добавлены совершенно новые операторы.
  5. ^ Бинарные функции с символическим именем можно назвать инфиксными.
  6. ^ «Предикат оп/3».
  7. ^ Хант, Джон (6 декабря 2012 г.). Smalltalk и объектная ориентация: введение. Springer Science & Business Media. ISBN 978-1-4471-0961-7.
  8. ^ "Бертран Мейер: Базовые механизмы языка Эйфеля". se.ethz.ch . Получено 7 апреля 2021 г. .
  9. ^ "Операторные функции в F90". www.mathcs.emory.edu . Получено 7 апреля 2021 г. .
  10. ^ Представлено в Fortran 90.
  11. ^ "3. Справочник по языку — документация Futhark 0.19.0". futhark.readthedocs.io . Получено 10 октября 2020 г. .
  12. ^ Смит, Крис (9 октября 2012 г.). Программирование F# 3.0: всеобъемлющее руководство по написанию простого кода для решения сложных проблем. O'Reilly Media, Inc. ISBN 978-1-4493-2604-3.
  13. ^ Классы типов вместо перегрузки.
  14. ^ "io guide". iolanguage.org . Получено 7 апреля 2021 г. .
  15. ^ «Операторы».
  16. ^ "Операторы - R в двух словах, 2-е издание [Книга]". www.oreilly.com . Получено 7 апреля 2021 г. .
  17. ^ «Создание операторов».
  18. ^ "Операторы". Экскурсия по Scala .
  19. ^ "Руководство Seed7: Определение структурированного синтаксиса". seed7.sourceforge.net . Получено 29 сентября 2020 г. .
  20. ^ «Swift: Продвинутые операторы».
  21. ^ "Почему Go не поддерживает перегрузку методов и операторов?" . Получено 4 сентября 2011 г.
  22. ^ "Введение". freepascal.org . Получено 30 сентября 2020 г. .
  23. ^ "Перегрузки операторов". GitHub . Получено 28 сентября 2018 г.
  24. ^ "6.6 Перегрузка операторов". Аннотированное справочное руководство по языку программирования Ada .
  25. ^ Дрейтон, Питер; Альбахари, Бен; Ньюард, Тед (2003). Коротко о C#. O'Reilly Media, Inc. ISBN 978-0-596-00526-9.
  26. ^ «Перегрузка операторов C++».
  27. ^ "Eclipse Ceylon: Операторный полиморфизм". ceylon-lang.org . Получено 7 апреля 2021 г. .
  28. ^ "Перегрузка операторов - язык программирования D". dlang.org . Получено 10 октября 2020 г. .
  29. ^ "Экскурсия по языку Dart". dart.dev . Получено 30 сентября 2020 г. .
  30. ^ "Перегрузка оператора". bourabai.kz . Получено 7 апреля 2021 г. .
  31. ^ "Язык программирования Apache Groovy - Операторы". groovy-lang.org . Получено 30 сентября 2020 г. .
  32. ^ "Перегрузка оператора". Коллектор . Получено 7 июня 2020 г.
  33. ^ "Перегрузка операторов". Kotlin . Получено 24 июня 2018 г. .
  34. ^ "Учебник метаметодов". Lua-users Wiki .
  35. ^ "Реализация операторов для вашего класса" . Получено 1 октября 2013 г.
  36. ^ "Перегрузка операторов". Free Pascal Manual . Получено 1 декабря 2014 г.
  37. ^ "Перегрузка операторов". Delphi Manual . Получено 1 декабря 2014 г.
  38. ^ "PHP magic methods overriding class properties". Архивировано из оригинала 4 марта 2016 года . Получено 7 апреля 2015 года .
  39. ^ Орвант, Джон (4 ноября 2002 г.). Компьютерная наука и программирование на Perl: лучшее из журнала Perl. O'Reilly Media, Inc. стр. 347–. ISBN 978-0-596-00310-4.
  40. ^ "3. Модель данных". Справочник языка Python .
  41. ^ "Методы". Официальный FAQ по Ruby .
  42. ^ "Перегрузка операторов". Rust на примере .
  43. ^ «Как: определить оператора (Visual Basic)». 15 сентября 2021 г.
  44. ^ =Барри Дж. Майлу "Отчет об алгоритмическом языке АЛГОЛ 68, раздел 10.2.2". Август 1968 г. Получено 1 апреля 2007 г. {{cite web}}: Проверить |url=значение ( помощь )
  45. ^ Страуструп, Бьярне . "История C++: 1979−1991" (PDF) . стр. 12. Получено 1 апреля 2007 г.
  46. ^ "FAQ Вопрос 6.9: Почему нет перегрузки операторов?". Список часто задаваемых вопросов comp.lang.java .
  47. ^ "java.sun.com". Архивировано из оригинала 7 марта 2009 г. Получено 26 марта 2009 г.
  48. ^ Хольцнер, Стивен (2001). С++: Черная книга . Скоттсдейл, Аризона: Группа Кориолиса. п. 387. ИСБН 1-57610-777-9. Одной из самых приятных особенностей ООП на языке C++ является возможность перегружать операторы для обработки объектов ваших классов (в некоторых других языках, ориентированных на ООП, например Java, этого сделать нельзя).
  49. ^ "3. Модель данных, Специальные имена методов". Справочник языка Python .