Перегрузка операторов
 
Способы изменения пользовательских объявляемых типов, работающих со встроенными операторами.

Обзор
Глобальные операторы
Операторы-элементы

Обзор

Если по простому, то операторы - это процедуры, а их аргументы называются операндами. Операторы, которые принимают один операнд (оператор Not) называются унарными операторами. Операторы, которые получают два операнда (оператор +) называются бинарными операторами. И операторы, принимающие три операнда (оператор Iif), называются тернарными операторами.

Большинство операторов не вызываются как процедуры. Вместо этого их символ оператора размещается рядом с их операндами. Для унарных операторов их единственный операнд помещается справа от символа. Для бинарных операторов их операнды размещаются слева и справа от символа оператора. FreeBASIC имеет один тернарный оператор, оператор Iif, и он как раз вызывается как процедура, а его операнды заключены в скобки и разделены запятыми. Например следующий код вызывает оператор Iif для определения допустимости указателя. Если это так, то вызывается оператор * (значение из),  для разыменования указателя, а если нет, то вызывается оператор / (деление), чтобы найти результат деления двадцати на четыре.

Dim i As Integer = 420
Dim p As Integer Ptr = @i

Dim result As Integer = IIf( p, *p, CInt( 20 / 4 ) )

Обратите внимание что оператор Iif  похож на вызов процедуры, а оператор * (значение из) и оператор / (деление) нет. В примере p является операндом оператора * (значение из) , а 20 и 4 являются левым и правым операндом  оператора / (деление).    

Все операторы в FreeBASIC предопределены для принятия операндов, имеющих стандартные типы данных, как например Integer и Single, но они могут быть также перегружены для определенных пользователями типов; то есть, они могут быть определены, чтобы принять операнды, которые являются объектами. Есть два типа операторов, которые могут быть перегружены, глобальные операторы и операторы-элементы.

Глобальные операторы

Глобальные операторы - это те, которые объявлены на уровня модуля (глобально). Это операторы - (инвертирование бит), Not (битовый Not), -> (указатель для доступа к элементу), * (значение из), + (сложение), - (вычитание), * (умножение), / (деление), \ (целочисленное деление), & (конкатенация), Mod (модуль числа), Shl (сдвиг бит влево), Shr (сдвиг бит вправо), And (битовый And), Or (битовый Or), Xor (битовый Xor), Imp (битовый Imp), Eqv (битовый Eqv), ^ (экспонента), = (равно), <> (не равно), < (меньше чем), > (больше чем), <= (меньше чем или равно) and >= (больше чем или равно).

Объявление пользовательского глобального оператора похоже на объявление процедуру. Ключевое слово Declare используется с ключевым словом Operator. Символ оператора стоит рядом с последующим списком параметров, разделенных запятыми и заключенные в скобки, которые будут представлять операнды передаемые оператору. В отличие от процедур, операторы перегружены по умолчанию, поэтому ключевое слово Overload не требуется при объявлении пользовательских операторов. По крайней мере, один из параметров оператора должны быть пользовательского типа (в конце концов, операторы со встроенными типами параметров уже определены).

В следующем примере декларируются глобальные операторы - (отрицание) и * (умножение) , принимающие операнды пользователем типа.

Type Rational
    As Integer numerator, denominator
End Type

Operator - (ByRef rhs As Rational) As Rational
    Return Type(-rhs.numerator, rhs.denominator)
End Operator

Operator * (ByRef lhs As Rational, ByRef rhs As Rational) As Rational
    Return Type(lhs.numerator * rhs.numerator, _
        lhs.denominator * rhs.denominator)
End Operator

Dim As Rational r1 = (2, 3), r2 = (3, 4)
Dim As Rational r3 = -(r1 * r2)
Print r3.numerator & "/" & r3.denominator

Здесь глобальные операторы определены для типа Rational, и используются в инициализации выражения для r3. Вывод: -6/12.

Операторы-элементы

Операторы-элементы декларируются внутри определения Type или Class, как процедуры-элементы, и они являются вычисляющими и присваивающими операторами Let (присваивание), Cast (преобразование), += (сложение и присваивание), -= (вычитание и присваивание), *= (умножение и присваивание), /= (деление и присваивание), \= (целочисленное деление и присваивание), ^= (возведение в степень и присваивание), &= (конкатенация и присваивание), Mod= (модуль числа и присваивание), Shl= (сдвиг бит влево и присваивание), Shr= (сдвиг бит вправо и присваивание), And= (конъюнкция и присваивание), Or= (инклюзивная дизъюнкция и присваивание), Xor= (эксклюзивная дизъюнкция и присваивание), Imp= (импликация и присваивание) and Eqv= (эквивалентность и присваивание).

При декларировании операторы-элементы используют ключевые слова Declare и Operator, а также символ оператора и его список параметров. Как процедуры-элементы, операторы-элементы определяются вне определения Type или Class, а имя символа дополняется префиксом имени Type или Class.

В следующем примере перегруженные операторы-элементы Cast (преобразование) и *= (умножение и присваивание) для объектов пользовательского типа.

Type Rational
    As Integer numerator, denominator
    
    Declare Operator Cast () As Double
    Declare Operator Cast () As String
    Declare Operator *= (ByRef rhs As Rational)
End Type

Operator Rational.cast () As Double
    Return numerator / denominator
End Operator

Operator Rational.cast () As String
    Return numerator & "/" & denominator
End Operator

Operator Rational.*= (ByRef rhs As Rational)
    numerator *= rhs.numerator
    denominator *= rhs.denominator
End Operator

Dim As Rational r1 = (2, 3), r2 = (3, 4)
r1 *= r2
Dim As Double d = r1
Print r1, d

Обратите внимание, что оператор-элемент Cast (преобразование) объявляется дважды, один раз для преобразования в Double и один раз для преобразования в String. Это единственный оператор (или процедура), который может быть объявлен несколько раз, когда отличается только тип возвращаемого значения. Компилятор сам решает, как обрабатывать перегрузку на основании того, как используется объект (в инициализации Double d, вызывается Rational.Cast as double, а в инструкции Print используется Rational.Cast as string).