Перегрузка оператора
Полиморфизм |
---|
Специальный полиморфизм |
Параметрический полиморфизм |
Подтипирование |
В компьютерном программировании перегрузка операторов , иногда называемая операторов специальным полиморфизмом , является частным случаем полиморфизма , когда разные операторы имеют разные реализации в зависимости от своих аргументов. Перегрузка операторов обычно определяется языком программирования , программистом или обоими.
Обоснование [ править ]
Перегрузка операторов является синтаксическим сахаром и используется, поскольку позволяет программировать с использованием нотации, более близкой к целевой области. [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 ) ».
Котлин поддерживает перегрузку операторов с момента своего создания.
См. также [ править ]
- Перегрузка функций
- Полиморфизм (информатика)
- Подпрограмма
- Оператор (программирование)
- Операторы в C и C++
- Метод мутатора
- Индексатор (программирование)
- Свойство (программирование)
Ссылки [ править ]
- ^ Страуструп, Бьерн . «Перегрузка оператора» . Часто задаваемые вопросы по C++ . Архивировано из оригинала 14 августа 2011 года . Проверено 27 августа 2020 г.
- ^ Фишер, Чарльз Н. (2008). «Проблемы перегрузки» (PDF) . Университет Висконсина-Мэдисона .
- ^ «Больше никакой перегрузки операторов» . Языковая среда Java . Корпорация Оракл .
- ^ Могут быть добавлены совершенно новые операторы.
- ^ Бинарные функции с символическим именем можно называть инфиксными.
- ^ «Предикат оп/3» .
- ^ Хант, Джон (6 декабря 2012 г.). Smalltalk и объектная ориентация: введение . Springer Science & Business Media. ISBN 978-1-4471-0961-7 .
- ^ «Бертран Мейер: Основные механизмы языка Эйфеля» . se.ethz.ch. Проверено 7 апреля 2021 г.
- ^ «Операторские функции в F90» . www.mathcs.emory.edu . Проверено 7 апреля 2021 г.
- ^ Представлено в Фортране 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 .
- ^ Введите классы вместо перегрузки.
- ^ «Ио-руководство» . iolanguage.org . Проверено 7 апреля 2021 г.
- ^ «Операторы» .
- ^ «Операторы — R в двух словах, 2-е издание [Книга]» . www.oreilly.com . Проверено 7 апреля 2021 г.
- ^ «Создание операторов» .
- ^ «Операторы» . Экскурсия по Скале .
- ^ «Руководство Seed7: Определение структурированного синтаксиса» . seed7.sourceforge.net . Проверено 29 сентября 2020 г.
- ^ «Свифт: Продвинутые операторы» .
- ^ «Почему Go не поддерживает перегрузку методов и операторов?» . Проверено 4 сентября 2011 г.
- ^ "Введение" . freepascal.org . Проверено 30 сентября 2020 г.
- ^ «Перегрузка операторов» . Проверено 28 сентября 2018 г.
- ^ «6.6 Перегрузка операторов» . Аннотированное справочное руководство по Ada .
- ^ Дрейтон, Питер; Альбахари, Бен; Ньюворд, Тед (2003). C# в двух словах О'Рейли Медиа, Инк. ISBN 978-0-596-00526-9 .
- ^ «Перегрузка операторов C++» .
- ^ «Eclipse Ceylon: Полиморфизм операторов» . ceylon-lang.org . Проверено 7 апреля 2021 г.
- ^ «Перегрузка операторов — язык программирования D» . dlang.org . Проверено 10 октября 2020 г.
- ^ «Экскурсия по языку дартс» . dart.dev . Проверено 30 сентября 2020 г.
- ^ «Перегрузка оператора» . bourabai.kz . Проверено 7 апреля 2021 г.
- ^ «Язык программирования Apache Groovy — Операторы» . groovy-lang.org . Проверено 30 сентября 2020 г.
- ^ «Перегрузка оператора» . Многообразие . Проверено 7 июня 2020 г.
- ^ «Перегрузка оператора» . Котлин . Проверено 24 июня 2018 г.
- ^ «Урок по метаметодам» . Lua-пользователи Wiki .
- ^ «Реализация операторов для вашего класса» . Проверено 1 октября 2013 г.
- ^ «Перегрузка оператора» . Бесплатное руководство по Паскалю . Проверено 1 декабря 2014 г.
- ^ «Перегрузка оператора» . Руководство по Делфи . Проверено 1 декабря 2014 г.
- ^ «Магические методы PHP, переопределяющие свойства класса» . Архивировано из оригинала 4 марта 2016 года . Проверено 7 апреля 2015 г.
- ^ Орвант, Джон (4 ноября 2002 г.). Информатика и программирование на Perl: лучшее из журнала Perl . O'Reilly Media, Inc., стр. 347–. ISBN 978-0-596-00310-4 .
- ^ «3. Модель данных» . Справочник по языку Python .
- ^ «Методы» . Официальный FAQ по Ruby .
- ^ «Перегрузка оператора» . Ржавчина на примере .
- ^ «Как определить оператор (Visual Basic)» .
- ^ =Барри Дж. Майу «Отчет об алгоритмическом языке АЛГОЛ 68, раздел 10.2.2» . Август 1968 года . Проверено 1 апреля 2007 г.
{{cite web}}
: Проверять|url=
ценность ( помощь ) - ^ Страуструп, Бьерн . «История C++: 1979–1991» (PDF) . п. 12 . Проверено 1 апреля 2007 г.
- ^ «Часто задаваемые вопросы, вопрос 6.9: Почему нет перегрузки операторов?» . Список часто задаваемых вопросов по comp.lang.java .
- ^ «java.sun.com» . Архивировано из оригинала 7 марта 2009 года . Проверено 26 марта 2009 г.
- ^ Хольцнер, Стивен (2001). С++: Черная книга . Скоттсдейл, Аризона: Группа Кориолиса. стр. 387. ИСБН 1-57610-777-9 .
Одна из самых приятных особенностей ООП C++ заключается в том, что вы можете перегружать операторы для обработки объектов ваших классов (вы не можете сделать это в некоторых других ООП-ориентированных языках, таких как Java).
- ^ «3. Модель данных, имена специальных методов» . Справочник по языку Python .