Перегрузка оператора - Operator overloading
Полиморфизм |
---|
Специальный полиморфизм |
Параметрический полиморфизм |
Подтип |
В компьютерное программирование, перегрузка оператора, иногда называемый оператор специальный полиморфизм, является частным случаем полиморфизм, где разные операторы имеют разные реализации в зависимости от аргументов. Перегрузка оператора обычно определяется язык программирования, а программист, или оба.
Обоснование
Перегрузка оператора есть синтаксический сахар, и используется, потому что он позволяет программировать с использованием нотации, близкой к целевой области[1] и предоставляет определяемым пользователем типам такой же уровень синтаксической поддержки, что и типы, встроенные в язык. Это распространено, например, в научных вычислениях, где позволяет манипулировать вычислительными представлениями математических объектов с тем же синтаксисом, что и на бумаге.
Перегрузка оператора не меняет выразительная сила языка (с функциями), поскольку его можно эмулировать с помощью вызовов функций. Например, рассмотрим переменные а
, б
и c
определенного пользователем типа, например матрицы:
а + б * в
На языке, который поддерживает перегрузку операторов, и с обычным предположением, что оператор '*' имеет большее значение приоритет чем оператор '+', это краткий способ написания:
Сложить (a, Умножить (b, c))
Однако первый синтаксис отражает обычное математическое использование.
Примеры
В этом случае оператор сложения перегружается, чтобы разрешить добавление для определенного пользователем типа. Время
в C ++:
Время оператор+(const Время& lhs, const Время& rhs) { Время темп = lhs; темп.секунды += rhs.секунды; темп.минут += темп.секунды / 60; темп.секунды %= 60; темп.минут += rhs.минут; темп.часы += темп.минут / 60; темп.минут %= 60; темп.часы += rhs.часы; возвращаться темп;}
Дополнение - это бинарная операция, что означает наличие двух операнды. В C ++ передаваемые аргументы - это операнды, а темп
объект - это возвращаемое значение.
Операция также может быть определена как метод класса, заменив lhs
скрытым это
аргумент; Однако это заставляет левый операнд иметь тип Время
:
// Эта «константа» означает, что | это | не модифицируется.// // ------------------------------------// |// VВремя Время::оператор+(const Время& rhs) const { Время темп = *это; // | это | не должны быть изменены, поэтому сделайте копию. темп.секунды += rhs.секунды; темп.минут += темп.секунды / 60; темп.секунды %= 60; темп.минут += rhs.минут; темп.часы += темп.минут / 60; темп.минут %= 60; темп.часы += rhs.часы; возвращаться темп;}
Обратите внимание, что унарный оператор, определенный как метод класса, не получит очевидного аргумента (он работает только с это
):
bool Время::оператор!() const { возвращаться часы == 0 && минут == 0 && секунды == 0;}
Оператор меньше (<) часто перегружается для сортировки структуры или класса:
учебный класс Пара { общественный: bool оператор<(const Пара& п) const { если (Икс_ == п.Икс_) { возвращаться y_ < п.y_; } возвращаться Икс_ < п.Икс_; } частный: int Икс_; int y_;};
Как и в предыдущих примерах, в последнем примере перегрузка оператора выполняется внутри класса. В C ++ после перегрузки оператора «меньше» (<) стандартные функции сортировки можно использовать для сортировки некоторых классов.
Критика
Перегрузка оператора часто подвергается критике[2] потому что он позволяет программистам переназначать семантику операторов в зависимости от типов их операндов. Например, использование <<
оператор в C ++:
а << б
сдвигает биты в переменной а
оставленный б
биты, если а
и б
имеют целочисленный тип, но если а
является потоком вывода, то приведенный выше код попытается написать б
к ручью. Поскольку перегрузка оператора позволяет исходному программисту изменить обычную семантику оператора и застать всех последующих программистов врасплох, считается хорошей практикой осторожно использовать перегрузку операторов (создатели Ява решил не использовать эту функцию,[3] хотя не обязательно по этой причине).
Другая, более тонкая проблема с операторами заключается в том, что некоторые математические правила могут быть неверно ожидаемы или непреднамеренно приняты. Например, коммутативность из + (т.е. а + Ь == Ь + а
) не всегда применяется; пример этого происходит, когда операнды являются строками, поскольку + обычно перегружается для выполнения конкатенации строк (т.е. "птица" + "песня"
дает "пение птиц"
, пока "песня" + "птица"
дает "певчая птица"
). Типичный счетчик[нужна цитата ] Этот аргумент исходит непосредственно из математики: хотя + коммутативен для целых чисел (и, в более общем смысле, для любого комплексного числа), он не коммутативен для других «типов» переменных. На практике + даже не всегда ассоциативный, например, со значениями с плавающей запятой из-за ошибок округления. Другой пример: в математике умножение коммутативно для действительных и комплексных чисел, но не коммутативно для матричное умножение.
Каталог
Классификация некоторых распространенных языков программирования производится в зависимости от того, могут ли их операторы перегружать программист и ограничены ли операторы предопределенным набором.
Операторы | Не перегружен | Перегружаемый |
---|---|---|
Новый определяемый[4] | ||
Ограниченный набор |
Хронология перегрузки оператора
1960-е
В АЛГОЛ 68 спецификация допускала перегрузку оператора.[37]
Выдержка из спецификации языка ALGOL 68 (стр. 177), где перегруженные операторы ¬, =, ≠ и пресс определены:
10.2.2. Операции над логическими операндамиa) op ∨ = (bool а, б) bool:( а | истинный | б); б) op ∧ = (bool а, б) bool: (a | b | ложный ); в) op ¬ = (bool а) bool: (а | ложный | истинный ); г) op = = (bool а, б) bool:( a∧b) ∨ (¬b∧¬a); e) op ≠ = (bool а, б) bool: ¬ (a = b); f) op пресс = (bool а)int: (а | 1 | 0);
Обратите внимание, что для перегрузка оператор, и программист может создавать новые операторы.
1980-е
Ада поддерживает перегрузку операторов с самого начала, с публикацией языкового стандарта Ada 83. Однако разработчики языка предпочли исключить определение новых операторов. Только существующие операторы в языке могут быть перегружены путем определения новых функций с такими идентификаторами, как «+», «*», «&» и т. Д. Последующие версии языка (в 1995 и 2005 гг.) Сохраняют ограничение на перегрузку существующих операторов. .
В C ++, перегрузка операторов более тонкая, чем в АЛГОЛ 68.[38]
1990-е годы
Ява языковые дизайнеры в Sun Microsystems решил опустить перегрузку.[39][40][41]
Рубин разрешает перегрузку оператора как синтаксический сахар для простых вызовов методов.
Lua позволяет перегрузку оператора в качестве синтаксического сахара для вызовов методов с добавленной функцией, согласно которой, если первый операнд не определяет этот оператор, будет использоваться метод для второго операнда.
2000-е
Microsoft добавила перегрузку операторов в C # в 2001 году и до Visual Basic .NET в 2003 г.
Scala обрабатывает все операторы как методы и, таким образом, допускает перегрузку операторов через прокси.
В Раку, определение всех операторов делегируется лексическим функциям, и поэтому, используя определения функций, операторы могут быть перегружены или добавлены новые операторы. Например, функция, определенная в Ракудо источник для увеличения объекта Date со знаком «+»:
мульти инфикс:<+>(Дата: D $ d, Инт: D $ x) { Дата.новичок($ d.дневной счет + $ x)}
Поскольку использовалось "multi", функция добавляется в список мультидиспетч кандидаты, а "+" перегружается только в том случае, если выполняются ограничения типа в сигнатуре функции. В то время как возможность перегрузки включает +, *, >=, то постфикс и термин я и так далее, он также позволяет перегрузить различные операторы фигурных скобок: "[х, у]", "Икс[ у ]", "Икс{ у }", и" x( у )".
Котлин поддерживает перегрузку операторов с момента его создания.
Смотрите также
- Перегрузка функций
- Полиморфизм (информатика)
- Подпрограмма
- Оператор (программирование)
- Операторы в C и C ++
- Метод мутатора
- Индексатор (программирование)
- Свойство (программирование)
Рекомендации
- ^ Страуструп, Бьярне. «Перегрузка оператора». C ++ FAQ. Архивировано из оригинал 14 августа 2011 г.. Получено 27 августа 2020.
- ^ Фишер, Чарльз Н. (2008). «Проблемы с перегрузкой» (PDF). Университет Висконсина-Мэдисона.
- ^ «Больше никаких перегрузок оператора». Языковая среда Java. Корпорация Oracle.
- ^ Могут быть добавлены совершенно новые операторы.
- ^ Бинарные функции с символическим именем можно называть инфиксными.
- ^ "Предикат op / 3".
- ^ Хант, Джон (6 декабря 2012 г.). Smalltalk и объектная ориентация: введение. Springer Science & Business Media. ISBN 978-1-4471-0961-7.
- ^ Представлен в Fortran 90.
- ^ "3. Справочник по языку - документация Futhark 0.19.0". futhark.readthedocs.io. Получено 10 октября 2020.
- ^ Смит, Крис (9 октября 2012 г.). Программирование F # 3.0: подробное руководство по написанию простого кода для решения сложных проблем. O'Reilly Media, Inc. ISBN 978-1-4493-2604-3.
- ^ Типовые классы вместо перегрузки.
- ^ «Создание операторов».
- ^ «Операторы». Экскурсия по Скале.
- ^ «Руководство по Seed7: определение структурированного синтаксиса». seed7.sourceforge.net. Получено 29 сентября 2020.
- ^ «Swift: продвинутые операторы».
- ^ «Почему Go не поддерживает перегрузку методов и операторов?». Получено 4 сентября 2011.
- ^ "Вступление". www.freepascal.org. Получено 30 сентября 2020.
- ^ «Перегрузка оператора». Получено 28 сентября 2018.
- ^ «6.6 Перегрузка операторов». Аннотированное справочное руководство по Ada.
- ^ Дрейтон, Питер; Альбахари, Бен; Ньюард, Тед (2003). C # в двух словах. O'Reilly Media, Inc. ISBN 978-0-596-00526-9.
- ^ «Перегрузка оператора C ++».
- ^ «Перегрузка оператора - язык программирования D». dlang.org. Получено 10 октября 2020.
- ^ «Экскурсия по языку Дарт». dart.dev. Получено 30 сентября 2020.
- ^ «Язык программирования Apache Groovy - Операторы». groovy-lang.org. Получено 30 сентября 2020.
- ^ «Перегрузка оператора». Многообразие. Получено 7 июн 2020.
- ^ «Перегрузка оператора». Котлин. Получено 24 июн 2018.
- ^ "Учебное пособие по метаметодам". Lua-пользователи Wiki.
- ^ «Реализация операторов для вашего класса». Получено 1 октября 2013.
- ^ «Перегрузка оператора». Руководство Free Pascal. Получено 1 декабря 2014.
- ^ «Перегрузка оператора». Руководство по Delphi. Получено 1 декабря 2014.
- ^ «Магические методы PHP, переопределяющие свойства класса». Архивировано из оригинал 4 марта 2016 г.. Получено 7 апреля 2015.
- ^ Орвант, Джон (4 ноября 2002 г.). Компьютерные науки и программирование на Perl: лучшее из журнала Perl. O'Reilly Media, Inc., стр. 347–. ISBN 978-0-596-00310-4.
- ^ «3. Модель данных». Справочник по языку Python.
- ^ «Методы». Официальный Ruby FAQ.
- ^ «Перегрузка оператора». Ржавчина на примере.
- ^ «Как: определить оператор (Visual Basic)».
- ^ Вейнгаарден, Адриан; Майю, Барри Дж.; Пек, Джон Э. Л.; Костер, Корнелис Х. А.; и другие. (Август 1968 г.). «Отчет по алгоритмическому языку АЛГОЛ 68, раздел 10.2.2» (PDF). Получено 1 апреля 2007.
- ^ Страуструп, Бьярне. «История C ++: 1979–1991» (PDF). п. 12. Получено 1 апреля 2007.
- ^ "FAQ Вопрос 6.9: Почему нет перегрузки оператора?". Список часто задаваемых вопросов о comp.lang.java.
- ^ "java.sun.com".
- ^ Хольцнер, Стивен (2001). C ++: Черная книга. Скоттсдейл, Аризона: Coriolis Group. п. 387. ISBN 1-57610-777-9.
Одна из самых приятных особенностей C ++ ООП заключается в том, что вы можете перегружать операторы для обработки объектов ваших классов (вы не можете сделать это в некоторых других языках, ориентированных на ООП, таких как Java).