PDA

Просмотр полной версии : [Урок] Перегрузка операторов



VVWVV
03.01.2017, 05:29
Всем привет!

В этом уроке я расскажу о перегрузке операторов.

Введение

В Pawn, как и в языке C++, присутствует перегрузка операторов. Она используется для изменения возвращаемого значения при какой-либо операции. Таким образом, она делает код более компактным, ведь при ином случае необходимо использовать обычные функции.

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

Ко всему прочему, имеет ряд ограничений. Например, вы не можете использовать оператор & для того, чтобы узнать адрес переменной. Кроме того, вы не можете использовать массивы/строки в аргументах. Хотя на этот счёт существует оператор emit, с помощью которого можно что-то сделать.

Поэтому следует всегда помнить, что перегрузка операторов - это всего лишь удобный способ вызова какой-либо функции.


Принцип работы

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

Пример перегрузки оператора:


stock
SomeTag:operator*(SomeTag:multiplicands, SomeTag:multiplier)
{
return SomeTag:((multiplicands * multiplier) + SomeTag:2);
}




Однако, как говорилось выше, имеется ряд ограничений:

Нельзя использовать оператор &, а также массивы в аргументах к оператору.
Ограниченное число операторов. Таким образом, вы не сможете перегрузить большую часть операторов.

Операторы не попавшие под ограничение:

Арифметические операторы ("=", "+" (сложение), "-" (вычитание), "+" (унарный плюс), "-" (унарный минус), "*", "/", "%", "++"(префиксный/постфиксный), "--" (префиксный/постфиксный)).
Операторы сравнения ("==", "!=", ">", "<", ">=", "<=").
Оператор логического НЕ ("!").




Если говорить о составных операторах, то они работают так, как и перегруженные. Например, у нас есть перегруженный +, то оператор += будет работать так, как и оператор + и т.д.



Для перегрузки оператора необходимо также знать его определение. Ниже приведена таблица с определениями операторов:


Оператор
Определение


Присваивание

SomeTag:operator=(SomeTag:a)


Сложение

SomeTag:operator+(SomeTag:a, SomeTag:b)


Вычитание

SomeTag:operator-(SomeTag:a, SomeTag:b)


Унарный плюс

SomeTag:operator+(SomeTag:a)


Унарный минус

SomeTag:operator-(SomeTag:a)


Умножение

SomeTag:operator*(SomeTag:a, SomeTag:b)


Деление

SomeTag:operator/(SomeTag:a, SomeTag:b)


Остаток от деления

SomeTag:operator%(SomeTag:a, SomeTag:b)


Инкремент (префиксный/постфиксный)

SomeTag:operator++(SomeTag:a)


Декремент (префиксный/постфиксный)

SomeTag:operator--(SomeTag:a)


Равенство

bool:operator==(SomeTag:a, SomeTag:b)


Неравенство

bool:operator!=(SomeTag:a, SomeTag:b)


Больше

bool:operator>(SomeTag:a, SomeTag:b)


Меньше

bool:operator<(SomeTag:a, SomeTag:b)


Больше или равно

bool:operator>=(SomeTag:a, SomeTag:b)


Меньше или равно

bool:operator<=(SomeTag:a, SomeTag:b)


Логическое отрицание, НЕ

bool:operator!(SomeTag:a)






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


stock // Ошибочный код
SomeTag:operator+(SomeTag:a, {Float,bool}:b)
{
return SomeTag:(_:a + _:b);
}


Для этого необходимо создать две функции:


stock
SomeTag:operator+(SomeTag:a, Float:b)
{
return SomeTag:(_:a + _:b);
}

stock
SomeTag:operator+(SomeTag:a, bool:b)
{
return SomeTag:(_:a + _:b);
}




Скорость

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

Читал комментарии некоторых пользователей, где они говорил, что выражение с перегруженным оператором быстрее, чем вызов нативной функции. Поэтому я решил аргументировать свой ответ. Приведу ассемблерный листинг (с использованием оператора):



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



Если же говорить лишь об использовании нативной функции, то вот листинг:



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


Копирование данной статьи на других ресурсах без разрешения автора запрещено!

DeimoS
03.01.2017, 06:51
она делает код более меньше

"более компактным" звучало бы лучше =)

VVWVV
03.01.2017, 06:54
"более компактным" звучало бы лучше =)

Да. Исправил.

KrutoyKrosch
03.01.2017, 06:57
https://pp.vk.me/c604631/v604631947/1cc43/tN8lIng6YMw.jpg

Зачем такая эксклюзивность?

VVWVV
03.01.2017, 06:59
https://pp.vk.me/c604631/v604631947/1cc43/tN8lIng6YMw.jpg

Зачем такая эксклюзивность?

Для развития данного форума. Например, для привлечения новых посетителей и т.п.

$continue$
03.01.2017, 20:15
В реальных условиях ползи от перегрузки в Pawn - мало. Например: оператор "==" не перегрузить для проверки строк (используя strcmp), т.к никак не передашь в функцию массив. Очень урезанная перегрузка. Технического применения ее почти нет.

И кстати в Cях нельзя же перегрузить операторы.

ziggi
03.01.2017, 22:47
И кстати в Cях нельзя же перегрузить операторы.

Там оно и не нужно. А в Pawn они есть исключительно из-за отсутствия типов и необходимости поддержки Float чисел.

Daniel_Cortez
03.01.2017, 23:18
В реальных условиях ползи от перегрузки в Pawn - мало. Например: оператор "==" не перегрузить для проверки строк (используя strcmp), т.к никак не передашь в функцию массив. Очень урезанная перегрузка. Технического применения ее почти нет.

И кстати в Cях нельзя же перегрузить операторы.
В исходниках Pawn частично реализована "привязка" к строковой библиотеке BString (https://github.com/compuphase/pawn/blob/master/include/bstring.inc). И, я так понимаю, единственное, что удерживает её от попадания в релиз - условия лицензии (двойное лицензирование под GPL и 3-пунктовой BSDL), накладывающие дополнительные ограничения на релиз в объектной форме. Тем не менее, можно доработать это поделие до плагина к SA-MP.

$continue$
03.01.2017, 23:37
Я к тому, что у автора в шапке темы "C/C++"

Там оно и не нужно. А в Pawn они есть исключительно из-за отсутствия типов и необходимости поддержки Float чисел.

VVWVV
04.01.2017, 22:09
В реальных условиях ползи от перегрузки в Pawn - мало. Например: оператор "==" не перегрузить для проверки строк (используя strcmp), т.к никак не передашь в функцию массив. Очень урезанная перегрузка. Технического применения ее почти нет.

И кстати в Cях нельзя же перегрузить операторы.

Да. Исправил.