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

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

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

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

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

a + b * c

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

Add(a, Multiply(b, c))

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

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

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

Time operator+(const Time& lhs, const Time& rhs) {
  Time 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:

// The "const" right before the opening curly brace means that |this| is not modified.
Time Time::operator+(const Time& rhs) const {
  Time temp = *this;  // |this| should not be modified, so make a copy.
  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 Time::operator!() const {
  return hours == 0 && minutes == 0 && seconds == 0;
}

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

class Pair {
 public:
  bool operator<(const Pair& p) const {
    if (x_ == p.x_) {
      return y_ < p.y_;
    }
    return x_ < p.x_;
  }

 private:
  int x_;
  int 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]

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

10.2.2. Operations on Boolean Operands
a) op ∨ = (bool a, b) bool:( a | true | b );
b) op ∧ = (bool a, b) bool: ( a | b | false );
c) op ¬ = (bool a) bool: ( a | false | true );
d) op = = (bool a, b) bool:( a∧b ) ∨ ( ¬b∧¬a );
e) op ≠ = (bool a, b) bool: ¬(a=b);
f) op abs = (bool a)int: ( a | 1 | 0 );

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

 prio max = 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 с помощью «+», следующая:

multi infix:<+>(Date:D $d, Int:D $x) {
    Date.new-from-daycount($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 .