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

Из Википедии, бесплатной энциклопедии

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

Обоснование [ править ]

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

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

a + b * c

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

Add(a, Multiply(b, c))

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

Примеры [ править ]

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

 времени  Оператор  +  (  const   Time  &   lhs  ,   const   Time  &   rhs  )   { 
   Time   temp   =   lhs  ; 
    темп  .   секунды   +=   правая шкала  .   секунды  ; 
    темп  .   минуты   +=   темп  .   секунды   /   60  ; 
    темп  .   секунды   %=   60  ; 
    темп  .   минуты   +=   правое час  .   минуты  ; 
    темп  .   часы   +=   темп  .   минут   /   60  ; 
    темп  .   минуты   %=   60  ; 
    темп  .   часы   +=   правая шкала  .   часы  ; 
   возврата    температура  ; 
  } 

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

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

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

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

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

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

class   Pair   { 
  public  : 
   bool   оператор  <  (  const   Pair  &   p  )   const   { 
     if   (  x_   ==   p  .  x_  )   { 
       return   y_   <   p  .   й_  ; 
      } 
     Верните   x_   <   p  .   Икс_  ; 
    } 

  Частное  : 
   int   x_  ; 
    интервал   y_  ; 
  }; 

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

Критика [ править ]

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

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

Каталог [ править ]

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

Операторы Не перегружаемый перегружаемый
Новое определяемое [4]
Ограниченный набор

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

1960-е годы [ править ]

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

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

10.2.2.   Операции с логическими операндами 
  а)  op  ∨ = (  bool  a, b)  bool  :( a |  true  | b ); 
  б)  op  ∧ = (  bool  a, b)  bool  : (a | b |  false  ); 
  в)  op  ¬ = (  bool  a)  bool  : (a |  false  |  true  ); 
  d)  op  = = (  bool  a, b)  bool  :( a∧b ) ∨ ( ¬b∧¬a ); 
  д)  op  ≠ = (  bool  a, b)  bool  : ¬(a=b); 
  е)  op   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 с помощью «+», следующая:

мультиинфикс   :<+>  (  Date:D   $d  ,  Int:D   $x  ) { 
      Дата  .   новое количество дней  (  $d  .  daycount  +  $x  ) 
  } 
 

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

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

См. также [ править ]

Ссылки [ править ]

  1. ^ Страуструп, Бьерн . «Перегрузка оператора» . Часто задаваемые вопросы по C++ . Архивировано из оригинала 14 августа 2011 года . Проверено 27 августа 2020 г.
  2. ^ Фишер, Чарльз Н. (2008). «Проблемы перегрузки» (PDF) . Университет Висконсина-Мэдисона .
  3. ^ «Больше никакой перегрузки операторов» . Языковая среда Java . Корпорация Оракл .
  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. ^ Представлено в Фортране 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. ^ «Ио-руководство» . iolanguage.org . Проверено 7 апреля 2021 г.
  15. ^ «Операторы» .
  16. ^ «Операторы — R в двух словах, 2-е издание [Книга]» . www.oreilly.com . Проверено 7 апреля 2021 г.
  17. ^ «Создание операторов» .
  18. ^ «Операторы» . Экскурсия по Скале .
  19. ^ «Руководство Seed7: Определение структурированного синтаксиса» . seed7.sourceforge.net . Проверено 29 сентября 2020 г.
  20. ^ «Свифт: Продвинутые операторы» .
  21. ^ «Почему Go не поддерживает перегрузку методов и операторов?» . Проверено 4 сентября 2011 г.
  22. ^ "Введение" . freepascal.org . Проверено 30 сентября 2020 г.
  23. ^ «Перегрузка операторов» . Проверено 28 сентября 2018 г.
  24. ^ «6.6 Перегрузка операторов» . Аннотированное справочное руководство по Ada .
  25. ^ Дрейтон, Питер; Альбахари, Бен; Ньюворд, Тед (2003). C# в двух словах О'Рейли Медиа, Инк. ISBN  978-0-596-00526-9 .
  26. ^ «Перегрузка операторов C++» .
  27. ^ «Eclipse Ceylon: Полиморфизм операторов» . ceylon-lang.org . Проверено 7 апреля 2021 г.
  28. ^ «Перегрузка операторов — язык программирования D» . dlang.org . Проверено 10 октября 2020 г.
  29. ^ «Экскурсия по языку дартс» . dart.dev . Проверено 30 сентября 2020 г.
  30. ^ «Перегрузка оператора» . bourabai.kz . Проверено 7 апреля 2021 г.
  31. ^ «Язык программирования Apache Groovy — Операторы» . groovy-lang.org . Проверено 30 сентября 2020 г.
  32. ^ «Перегрузка оператора» . Многообразие . Проверено 7 июня 2020 г.
  33. ^ «Перегрузка оператора» . Котлин . Проверено 24 июня 2018 г.
  34. ^ «Урок по метаметодам» . Lua-пользователи Wiki .
  35. ^ «Реализация операторов для вашего класса» . Проверено 1 октября 2013 г.
  36. ^ «Перегрузка оператора» . Бесплатное руководство по Паскалю . Проверено 1 декабря 2014 г.
  37. ^ «Перегрузка оператора» . Руководство по Делфи . Проверено 1 декабря 2014 г.
  38. ^ «Магические методы PHP, переопределяющие свойства класса» . Архивировано из оригинала 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. ^ «Перегрузка оператора» . Ржавчина на примере .
  43. ^ «Как определить оператор (Visual Basic)» .
  44. ^ =Барри Дж. Майу «Отчет об алгоритмическом языке АЛГОЛ 68, раздел 10.2.2» . Август 1968 года . Проверено 1 апреля 2007 г. {{cite web}}: Проверять |url= ценность ( помощь )
  45. ^ Страуструп, Бьерн . «История C++: 1979–1991» (PDF) . п. 12 . Проверено 1 апреля 2007 г.
  46. ^ «Часто задаваемые вопросы, вопрос 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 .