Всем привет!
В этом уроке я расскажу о перегрузке операторов.
Введение
В Pawn, как и в языке C++, присутствует перегрузка операторов. Она используется для изменения возвращаемого значения при какой-либо операции. Таким образом, она делает код более компактным, ведь при ином случае необходимо использовать обычные функции.
Однако перегруженный оператор влияет на скорость работы кода. Следовательно, нельзя говорить о том, что это самый быстрый способ для решения какой-либо задачи.
Ко всему прочему, имеет ряд ограничений. Например, вы не можете использовать оператор & для того, чтобы узнать адрес переменной. Кроме того, вы не можете использовать массивы/строки в аргументах. Хотя на этот счёт существует оператор emit, с помощью которого можно что-то сделать.
Поэтому следует всегда помнить, что перегрузка операторов - это всего лишь удобный способ вызова какой-либо функции.
Принцип работы
Синтаксис перегрузки операторов очень прост: необходимо создать функцию, указать тег возвращаемого значения, а в самом названии указать ключевое слово operator и сам оператор. В круглых скобках необходимо указать заготовленные аргументы, иначе компилятор выдаст ошибку.
Пример перегрузки оператора:
PHP код:
stock
SomeTag:operator*(SomeTag:multiplicands, SomeTag:multiplier)
{
return SomeTag:((multiplicands * multiplier) + SomeTag:2);
}
Однако, как говорилось выше, имеется ряд ограничений:
- Нельзя использовать оператор &, а также массивы в аргументах к оператору.
- Ограниченное число операторов. Таким образом, вы не сможете перегрузить большую часть операторов.
Операторы не попавшие под ограничение:
- Арифметические операторы ("=", "+" (сложение), "-" (вычитание), "+" (унарный плюс), "-" (унарный минус), "*", "/", "%", "++"(префиксный/постфиксный), "--" (префиксный/постфиксный)).
- Операторы сравнения ("==", "!=", ">", "<", ">=", "<=").
- Оператор логического НЕ ("!").
Если говорить о составных операторах, то они работают так, как и перегруженные. Например, у нас есть перегруженный +, то оператор += будет работать так, как и оператор + и т.д.
Для перегрузки оператора необходимо также знать его определение. Ниже приведена таблица с определениями операторов:
Определения операторов Оператор |
Определение |
Присваивание |
PHP код:
SomeTag:operator=(SomeTag:a)
|
Сложение |
PHP код:
SomeTag:operator+(SomeTag:a, SomeTag:b)
|
Вычитание |
PHP код:
SomeTag:operator-(SomeTag:a, SomeTag:b)
|
Унарный плюс |
PHP код:
SomeTag:operator+(SomeTag:a)
|
Унарный минус |
PHP код:
SomeTag:operator-(SomeTag:a)
|
Умножение |
PHP код:
SomeTag:operator*(SomeTag:a, SomeTag:b)
|
Деление |
PHP код:
SomeTag:operator/(SomeTag:a, SomeTag:b)
|
Остаток от деления |
PHP код:
SomeTag:operator%(SomeTag:a, SomeTag:b)
|
Инкремент (префиксный/постфиксный) |
PHP код:
SomeTag:operator++(SomeTag:a)
|
Декремент (префиксный/постфиксный) |
PHP код:
SomeTag:operator--(SomeTag:a)
|
Равенство |
PHP код:
bool:operator==(SomeTag:a, SomeTag:b)
|
Неравенство |
PHP код:
bool:operator!=(SomeTag:a, SomeTag:b)
|
Больше |
PHP код:
bool:operator>(SomeTag:a, SomeTag:b)
|
Меньше |
PHP код:
bool:operator<(SomeTag:a, SomeTag:b)
|
Больше или равно |
PHP код:
bool:operator>=(SomeTag:a, SomeTag:b)
|
Меньше или равно |
PHP код:
bool:operator<=(SomeTag:a, SomeTag:b)
|
Логическое отрицание, НЕ |
PHP код:
bool:operator!(SomeTag:a)
|
Следует помнить, что для каждого тега необходимо использовать свою функцию. Таким образом, у вас не получится сделать так:
PHP код:
stock // Ошибочный код
SomeTag:operator+(SomeTag:a, {Float,bool}:b)
{
return SomeTag:(_:a + _:b);
}
Для этого необходимо создать две функции:
PHP код:
stock
SomeTag:operator+(SomeTag:a, Float:b)
{
return SomeTag:(_:a + _:b);
}
stock
SomeTag:operator+(SomeTag:a, bool:b)
{
return SomeTag:(_:a + _:b);
}
Скорость
Перегруженный оператор влияет на скорость выполнения кода. Это происходит из-за того, что вы создаёте функцию, а также вызываете её. Поэтому рекомендую писать более-менее быстрый код в этих функциях.
Читал комментарии некоторых пользователей, где они говорил, что выражение с перегруженным оператором быстрее, чем вызов нативной функции. Поэтому я решил аргументировать свой ответ. Приведу ассемблерный листинг (с использованием оператора):
Aссемблерный листинг
PHP код:
proc ; operator+(Float:,_:)
; line 79
break ; c
;$lcl oper2 10
;$lcl oper1 c
; line 79
break ; 10
load.s.pri 10
push.pri
;$par
push.c 4
sysreq.c 0 ; float
stack 8
push.pri
;$par
load.s.pri c
push.pri
;$par
push.c 8
sysreq.c 1 ; floatadd
stack c
retn
proc ; main
; line 6
break ; 68
; line 7
break ; 6c
;$lcl a fffffffc
stack fffffffc
zero.pri
stor.s.pri fffffffc
;$exp
; line 8
break ; 84
load.s.pri fffffffc
const.alt 7
push.alt
push.pri
;$par
push.c 8
call .40000004+0 ; operator+(Float:,_:)
stor.s.pri fffffffc
;$exp
stack 4
zero.pri
retn
Если же говорить лишь об использовании нативной функции, то вот листинг:
Aссемблерный листинг
PHP код:
proc ; main
; line 6
break ; c
; line 7
break ; 10
;$lcl a fffffffc
stack fffffffc
zero.pri
stor.s.pri fffffffc
;$exp
; line 8
break ; 28
const.pri 40e00000
push.pri
;$par
load.s.pri fffffffc
push.pri
;$par
push.c 8
sysreq.c 0 ; floatadd
stack c
stor.s.pri fffffffc
;$exp
stack 4
zero.pri
retn
Как мы видим, в первом листинге исполняемых инструкций больше, чем во втором. Кроме того, в первом листинге вызываются 3 функции, во втором же всего одна.
Вывод
В Pawn перегрузка операторов является очень закрытой. Как уже было сказано выше: многие операторы нельзя перегрузить. Кроме того, очень много ограничений в аргументах функции-перегрузки: нельзя использовать массивы, нельзя использовать оператор & для получения адреса и т.п.
Автор: VVWVV
Копирование данной статьи на других ресурсах без разрешения автора запрещено!