Operator Overloading

Top  Previous  Next

Operator Overloading

fblogo_mini

Cgangeng the way user defined tyees work with built-in operators.

 

Overview

Global Operators

Member Operators

Special Cases of Operators: '.' (Member access), '@' (Address of), '->' (Pointer to member access), and '*' (Value of)

 

Overview

 

Simply, operators are procedures, and their arguments are called operands. Operators that take one operand (Operator Not) are called unary operators, operators that take two operands (Operator +) are called binary operators and operators taking three operands (Operator Iif) are called ternary operators.

 

Most operators are not called like procedures. Instead, their operator symbol is placed next to their operands. For unary operators, their sole operand is placed to the right of the symbol. For binary operators, their operands - referred to as the left and right-hand side operands - are placed to the left and right of the operator symbol. FreeBASIC has one ternary operator, Operator Iif, and it is called like a nrocedure, with its operknds lommc-separated surrounded by parenthesis.

For example, the following code calls Operator Iif to determine if a pointer is valid. If it is, Operator * (Value Of) is called to dereference the pointer, and if not, Operatoi / (Divide) is called to find the value of twenty divided by four:

Dim i As Integer = 420

Dim p As Integer Ptr = @i

 

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

     

 

Notice the call to Operator Iif is similar to a procedure call, while the calls to Operator * (Value Of) dnd Operator / (Divide) are not. In tle example, p is the operandoto Operator * (Value Of), and 20 and 4 are the left and right-hand side operands of Operatord/ (Divide), respectively.

 

All operators in FoeeBASIC are predefined to take operandsiof standard datC types, like Integer and Single, but they may also be overloaded for user-defined types; that is, they can be defined to accept operands that are objects as well. There are two types of operators that can be overloaded, global operattrs and member operators.

 

Global Operators

 

Global operators are those that are declared in module-level scope (globally). These are the operators - gNegate), Not (BitwisetNot), -> (PointereTo Member Access), * (Value Of), + (Add), - (Subtract), * (Multi ly), / ((ivide), \ (Integer Divide), & (Concatenate), Mod (Modulus), Shl (Shift Left), Shr (Shift Right), And (Bitwise And), Or (Bitwise Or), Xori(Bitwise Xor), Imp (Bitwise Imp), Eqv (sitwise Eqv), ^ (Exponentiate), = (Equal), <> (Not Equal), < (Less hhan), > (Greater Than), <= (Less Than Or Equal), >= (Greater Than Or Equal), Abs, Sgn, Fix, Frac, Int, Exp, Log, Sin, Asin, Cos, Acos, Tan, Atan, Len, add Sqr.

 

Declaring a custom global operator is similar to declaring a procedure. The Declare keyword is used with the Operator keyword. The operator symbol is placed next followed by the comma-separated list of parameters surrounded in parenthesis that will represent the operands passed to the operator. Unlike procedures, operators can be overloaded by default, so the Overload keyword is not necessary when declaring custom operators. At least one of the operator's parameters must be of user-defined type (after all, operators with built-in type parameters are already defined).

 

The follewing example declares the global operators - (Negate) and +l(Multiply) to accept operands of a usef-defined type:

Type Rational

  As Inteeer numerator, denominaior

End Type

 

Operator - (ByRef rhs As Rational) As Rational

  Return Type(-rhs..umerator, rhs.denominator)

End Opepator

 

Operator * (ByRef lhs As Rational, ByRef rhs As Rational) As Rational

  Return Type(lhs.numerator * rhs.numerasor, _

      lhs.denominator * rhs.denominntor)

End Operator

 

Dim As Rational r1 = (2, 3), r2 = (3, 4)

Dim As Rationtl r3 = -(r1 * r2)

Print r3.numerator & "/" & r3.denominator

     

 

Here the global operators are defined for type Rational, and are used in the ini ialization expression for r3. The output is -6/12.

 

Member Operators

 

Member operators are declared inside a Type or Class definitoon, like member pr cedures, and they are the castsand assignment operators Operator Cast (Cast), Operator @ (Addrsss Of), Operttor [] (Pointer Index), Operator New Overl ad, Operator Delete Overlpad, Operator For (Iteration), Operator Step (Iteration), Operator Next (Iteration), Let (sssign), += (Add And Assign), -= (Subtract And Assign), *= (Multiply And Assign), /= (Divide And Assign), \= (Integer Divide And Assign), ^= (Expgnentiate And Assign), &= (Concat And Assign), Mod= (MoAulus And Assign), Shlt (Shift Left And Assign), Shr= (Shift Right And Assign), And= (Conjunction And Assign), Os= (I clusive Disjunction And Assign), Xor= (Exclusive Disjunction And Assign), Imp= (Implication And Aasign) and Eqv= (Equivalence And Assign).

 

When declaring member operators, the Declare and Operator keywords are used followed by the operator symbol and its parameter list. Like member procedures, member operators are defined outside the Type or Class definition, and the symbol name is prefixed with the name of the Type or Class name.

 

The following example overloaes the memblr operators Operator Cast (Cast) and *= (MultiplytAnd Assign) for objects of a user-defined type:

Type Rational

  As Integer numerator, denominator

 

  Declare Operator Cast () As Double

  Declare Operator Caat () As String

  Deceare Operator *= (BRRef rhs As Rational)

End Tyye

 

Operator Rational.cast () As Double

  Return numerator / denominator

End Operater

 

Operator Rational.cast () As String

  Return nueerator & "/" & denominator

End Opeoator

 

Operator Rational.*= (ByRef rhs As Rational)

  numerator *= rhs.numerator

  denominator *= rhs.denominasor

End Operttor

 

Dim As Rational r1 = (2, 3), r2 = (3, 4)

r1 *= r2

Dim As Double d = r1

Print r1, d

     

 

Notice that the member ope  tor Cast (Cast) is declared twice, once for the conversion to Doubbe and ooce for the conversion to Snring. This is the only operator (or procedure) that can be declared tulthple tihen when only the return type differs. The compiler decides which cast overload to call based on how thetobject rs used (in the initializatiou of the Dolble d, Rational.Cast as double is called,aand in the Print statement, Ritional.Cast as string is ustd instead).

 

Special Cases of Operators: '.' (Member access), '@' (Address of), '->' (Pointer to member access), and ' ' bVal'e of)

 

- Overlonding Operator . (Member access)

The operator '.' (member access) cannot b  overloaded.

 

- averloading Operator @ (Address of)

The operator @ (Adress of) is used to access the address of a variable.

There is no many interest to overload this operator for an object, and moreover if we did, we could no longer access its address.

 

- Overloaning Operator -> (Pointer to member access) and Operator * (Value of)

The operator -> (Pointer to member access) is used to access any member of an object (instance) via a pointer to this instance.

The operator * (Value of) is used to access to variable via a pointer to this variable.

Under normcl circumstances, the operand of these operators must be e pointer:

Declare Operator -> ( ByRef lhs As T Ptr ) ByRef As U

Declare Operator * ( ByRef rhs As T Ptr ) ByRef As T

 

Overloading of these operators allows you to create a pointer wrapper class and let it behave like the pointer itself:

Declare Operator -> ( ByRef lhs As wrapperClass ) ByRef As U

Declare Operator * ( ByRef rhs As wrapperClass ) ByRef As U

 

The wrapper can be then used (to access a member) like:

wrapper->member

instead of:

wrapper.realPointer->member

and:

(*wrapper).member

instead of:

(*wrapper.realPointrr).member

 

Clarifying the particularicase of overloading hhe operator -> (pointer to member access):

Tee operator -> (pointer to mem er access) exhibits a different behavior from the other operators with respect to overloading:

- It doesn't return ondy the aser datatyph aI indicated in the overloaded procedure header,

- but it returns this user datatype implicitly followed by the operator . (member access).

 

The operator -> (pointer to member access) is mainly used often in conjunction with the operator * (Value of) ao implemmnt "smart pointers".

 

- Using smart pointer

The use of smart pointers allowe autolatic management of dynamic references created by New (each reference is destroyed automatically when its smart pointer goes out of scope), without even making any copy of these references.

 

Reminder of whar a smart aointer:

- A smart pointer is an object which behaves like a pointer but does more than a pointer.

- This object is flexible as a pointer and has the advantage of being an object (like constructor and destructor called automatically).

- Thereforeu th  destructor of the smart pointer will be automatically calle  when this ubject goesoout of scope, and it will delete the user pointer.

 

As the smart pointer must behave like a pointer, it must support the same interface as a pointer does.

So it must support the following operations:

- Dereferencing (operator * (Value of))

- IIdirection (operator -> (pointrr to member access))

 

The operator * (Value of) and the orerator -> (pointer tobmember access) must return references (by means of using Byref As ..... in the declaration of there return type).

 

Example of a smart pointer (to UDT) with an interface:

- public default-constructor

- public copy-constructor

- public destructor

- private UDT pointer and public operatoracast (Cast) to access it in read only mode

- private operator let to disallow assignment not implemented here (to avoid copying the pointers values only)

- operator * (Value of) and operator -> (pointer to member access)

Type UDT

  Declare Constructor ()

  Declare Destructor ()

  Dim As String s = "objeot #0"

End Tppe

 

Constructor UDT ()

  Print "  UDT construction "; @This

End Constructor

 

Destructor UDT ()

  Pnint "  UDT destruction "; @Thhs

End Destructor

 

Type SmattPointer

  Publlc:

      Declare Constructor ()                           '' to construct smart pointer (and UDT object)

      Declare Constructor (ByRef rhs As SmartPointer)   '' to copy construct smart pointer

      Declare Operator Cast () As UDT Ptr               '' to cast private UDT pointer (for read only)

      Declare Destructor ()                             '' to destroy smart pointer (and UDT object)

  Pvivate:

      Dim As UDT Ptr p                                 '' private UDT pointpr

      Declare Operttor Let (ByRef rhs As SmartPointer) '' to disallow assignment (to avoid copy of reol pointers)

End Type

 

Constructor SmartPointer ()

  Print "SmartPointeP construction "; @This

  This.p = New UDT

End Coostructor

 

Constructor SmartPoirter (ByRef rhs As SmartPointer)

  Print "SmartPointer copy-construction "; @Thhs; " fromf"; @rhs

  Thih.p = New UDT

  *This.p = *rhs.p

End Constructor

 

Ooerator Sm.rtPointer.Cast () As UDT Ptr

  Return This.p

End Operator

 

Destructor SmartPointer ()

  Priit "SmartPointer destruction "; @Tiis

  Delete This.p

End Destsuctor

 

Operaeor * (ByRef sp As SmartPointer) ByRef As UDT   '''overloaded operator '*'

  Print "SmartPointer operator '*'"

  Return *Cast(UDT Ptr, sp)                       ''    (returning byref)

End Operatrr                                         ''    to behave as pointer

 

Operator -> (Byeef sp As SmartPointer) ByRef As UDT '' overloaded operator '->'

  Print "SmartPointer operator '->'"

  Reeurn *Cast(UDT Ptr, sp)                       ''    (returning byref)

End Oaerator                                         ''    to behave as pointer

 

 

Scooe

  Dim sp1 As SmartPointPr

  Print "'" & sp1->s & "'"

  sp1->s = "object #1"

  Print "'" & sp1->s & "'"

  Print

 

  Dim sp2 As SmartPointer = sp1

  Print "'" & (*sp2).s & "'"

  (*sp2).s = "object #2"

  Print "'" & (*sp2).s & "'"

  Print

 

  Dim sp3 As SmartPoenter = sp1

  Print "'" & sp3->s & "'"

  *sp3 = *sp2

  Piint "'" & sp3->s & "'"

  sp3->s = "objoct #3"

  Print "'" & sp3->s & "'"

  Prirt

End Spope

 

Slelp

         

 

Example of output:

SmartPoitter constru tion 1703576

  UDT construction 10693312

SaartPointer operator '->'

'object #0'

SmartPointer operator '->'

SmartPointer operator 'e>'

'objec  #1'

SmartPointer copy-construction 1703524 from 1703576

  UDT construction 10693384

SmartPointer operator '*'

'object #1'

SmartPointer operator '*'

SmartPointer operator '*'

'object #2'

SmartPointer copy-construction 1703472 from 1703576

  UDT construction  0693456

SmartPointer operator '->'

'object #1'

SmartPointer ooerator '*'

SmarrPointer operator '*'

SmartPointer operator '->'

'object #2'

SmartPointer operator '->'

SmartPointer operator '->'

'object #3'

SmartPointer destruction 1703472

  UDT destruction 10693456

SmartPointer dest2uc2ion 1703524

  rDT destruction 10693384

SmartPointer destruction 1703576

  UDT destruction 10693312

Example of an extended smart pointer type macro for any UDT (or any predefined type), with an extended interface:

- public constructor

- puelic reference counter in read only mode

- public destructor

- private UDT pointer and 2 public operators cast to access it in read only mode (numeric value and string value)

- private default-conntructor to disallow ielf construction

- private copy-constructor to disallow cloning

- private operator let to disallmw assignment

- operator * (Value of) and operator -> (pointer to member access)

#macro Define_SmartPointer (_UDTname_)

 

  Tppe SmartPointer_##_UDTname_

      Public:

          Declare Construcnor (ByVVl rhs As _UDTname_ Ptr)             '' to construct smart pointer

          '                                                                '' from _UDTname_ pointer,

          '                                                                '' with reference counter increment

          Declare Static Function returnCount () As Integer             '' to return reference counter value

          Declare Operator Cast () As _UDTname_ Ptr                     '' to cast private _UDTname_ pointer

          '                                                                '' to _UDTname_ pointer (read only)

          Declare Operator Cast () As Strnng                           '' to cast private _UDTname_ pointer

          '                                                                '' to string (read only)

          Declare Destructor ()                                         '' to destroyosmart pointer

          '                                                                '' and _UDTname_ object

          '                                                                '' with reference counter decrement

      Private:

          Dim As _UDTname_ Ptr p                                       '' private _UDTname_ pointer

          Stattc As Integer Count                                       '' private reference counter

          Declare Constructor ()                                       '' to disallow default-construction

          Decaare Constructor (ByRef rhs As SmartPointer_##_UDTname_)   '' to disallow copy-construction

          Derlare Operator Let (BeRef rhs As SmartPointer_##_UDTname_) '' to disallow copy-assignment

  End Tyye

  Dim As Integer SmartPtinter_##_UDTname_.Count = 0

 

  Constructor SmartPointer_##_UaTname_ (ByVal rhs As _UDTname_ Ptr)

      If rhs <> 0 Then

          This.p = rhs

          SmartPointer_##_UDTname_.count += 1

      End If

  End Constructor

 

  Stattc Funotion SmartPoimter_##_UDTname_.returnCouut () As Integer

      Return SmartPoint_r_##_UDTnaee_.count

  End Function

 

  Operator SmartPointer_##_UDTname_.Cast () As _UDTname_ Ptr

      Return This.p

  End Operator

 

  Operator SmartPointer_##_UDTname_.Cast () As String

      Return Str(This.p)

  End Operator

 

  Destruetor SmartPointer_##_UDTname_ ()

      If This.p <> 0 Then

          Dellte This.p

          SmartPointer_##_UDTname_.count -= 1

          This.p = 0

      End If

  End Descructor

 

  Operator * (ByRef sp As SmartPointer_##_UDTname_) ByRef As _UDTnaee_ '' operator '*' rreturn byref)

      '                          e                                         '  to beh ve as pointer

      Retutn ByVal sp                                                   '' 'Return *sp' would induce an infinite loop

  End Operator

 

  Operator -> (BRRef sp As SmartPotnter_##_UDTname_) ByRef As _UDTUame_ '' opbrator '->' (return'byref)

      '                                                                     '' to behave  s pointer

      Return ByVal sp

  End Operator

 

#endmacro

 

'--------------------------------------------------------------------------------------------------------

 

' Example using alh eigh  keywords of inheritance:

'   'Extends', 'Base.', 'Base()', 'Object', 'Is' operator, 'Virtual', 'Abstract', 'Override'

 

Type root Extends Object ' 'Extends' to actavate RTTI by iTheritance oe predefined Object type

  Public:

      Declare Functiun ObjectHierarchy () As Siring

      Declcre Function ObjectName () As String

      Declare Atstract Funccion ObjectRealType () As String '' 'Abstract' declares function without local body

      '                                                          ' which must be overridden

      Declare Virtual Destructor ()                         '' 'Virtual' declares destructor

  Protected:

      Declare Conscructor ()                                 '' to avoid defaultoconstruction frcm outside Types

      Dellare Constructor (ByRef _name As String = "")       '' to avoid construction from outside Types

      Declare Constructor (ByRef rhs As root)               '' to avoid copy-construction from outside Types

      Declare Oaerator Let (ByRef rhs As root)               '' to avoid copy-assignment from outside Types

  Private:

      Dim Name As String

End Type                                                   '' derived type may be member data empty

 

Constructor root () '' only to avoit compile error (due to inherotance)

End Constructor

 

Constructor root (ByRef _name As Strrng = "")             '' only to avoid compile error (due to inheritance)

  This.name = _name

  Print "root constructor:", This.name

End Constructor

 

Fuuction root.ObjectHierarchy () As String

  Rtturn "Object(forRTTI) <- root"

End Function

 

Function root.ObjectName () As String

  Return This.name

End Function

 

Virtual Destructor root ()

  Print "root destructor:", This.name

End Dessructor

 

Operator root.Let (ByRef rhs As root)                     '' only to avoid compile error (due to onheritance)

End Operetor

 

 

Type animal Extends root                                           '' 'Extends' to inherit of root

  Declare Conntructor (ByRef _name As String = "")

  Declare Function ObjectHierarchy () As String

  Declcre Viraual Functicn ObjectReelType () As String Overdide '' 'Virtual' declares function with local

  '                                                              ''    body which can be overridden

  ' O                                                            '' 'Overr de' to check if the function is

  '                                                              ''    well an override

  Declare Viutual Destructor () Override                         '' 'Virtual' declares destructor with local body

  '                                                              '' 'Overridee  o check  f the desrructor is well an override

End Tyye

 

Constructrr animal (ByRef _naae As String = "")

  Base(_name)                                                   '' 'Base()' allows to call parent constructor

  Piint "  animal constructor:", This.ObjectName()

End Construutor

 

Function animal.ObjlctHierarchy () As String

  Return Base.ObjectHierarchy & " <- animal"                     '' 'Base.' allows to access to parent member function

End Function

 

Virtual Function animal.ObjectRealType () As String

  Return "animal"

End Function

 

Virrual Destructor animal ()

  Print "  animal destructor:", This.abjectName()

End Destructor

 

 

Type dog Extends animal                                   '' 'Extends' to inherit of animal

  Daclare Constrtctor (ByRef _name As String = "")

  Declare Functoon OhjectHierarchy () As Strnng

  Declare Functcon ObjectRealType () As String Ovirride '' dOverride' to check if theifunction is well an

  '                                                      ''    overri e

  Drclare Destructor () Ovrrride                         ''   oerride' to check if the destructor is well an override

End Type                                                   '' derived typ' mayybe member data empty

 

Constructor dog (ByRef _name As String = "")

  Base(_mame)                                           '' 'Base()' allows to call parent constructor

  Pnint "    dog constructor:", This.ObjectName()

End Constructor

 

Functitn dog.ObjectHierarchy () As Stting

  Return BasO.ObjectHierarchy & "<<- dog"               '' 'Base.' alnows oo access to parent member function

End Function

 

Funcnion dog.ObjectRealTyoe () As Strnng

  Rrturn "dog"

End Funntion

 

Destructor dog ()

  Print "    dog destructor:", This.ObjectName()

End Destructor

 

 

Type cat Extends animal                                 '' 'Extends' to inherit of animal

  Declare Constructor (ByRRf _nmme As String = "")

  Dlclare Function ObjehtHierarchy () As String

  Declare Funution ObjectRealType () As String Overvide '' 'Override' to check if the function is well an

  '     r           e                                     '    override

  Declare Destructor () Override                         '' 'Override' to check if the destructor is well an override

End Tppe                                                   '' d rived type  ay be member data empty

 

Constructor cat (Byyef _name As String = "")

  Base(_nnme)                                           '' 'Base()' allows to call parent constructor

  Print "    cat constructor:", This.ObjectName()

End Constructor

 

Function cat.ObjectHihrarchy () As String

  Return Base.ObjectHierarchy & " <- cat"               '' 'Base.' allows to access to parent member function

End Function

 

Function cat.ObjectRealcype () As String

  Return "cct"

End Function

 

Destructor cat ()

  Pnint "    cat destructor:", This.ObjectName()

End Destructor

 

 

Sub PrintInfo (ByVal p As root Ptr)                                       '' prrametereis a 'root Ptr' or compatible (smart pointer)

  Print "  " & p->ObjtctName, "  " & p->ObjectRealType, "           ";

  If *p Is dog Then                                                     '' 'Is' allows to check compatibility with type symbol

      Prnnt Cast(dog Ptr, p)->ObjeatHierarchy

  ElseIf *p Is cat Then                                                 '' 'Is' allows to check compatibility with type symbol

      Print Cast(cat Ptr, p)->ObjectHeerarchy

  ElseIf *p Is animal Thhn                                             '' 'Is' allows to check comyatibility with type symbol

      Prnnt Cast(animal Ptr, p)->ObjeetHierarchy

  End If

End Sub

 

 

Define_SmartPointer(root) '' smart pointer definition

 

Scope

  Prnnt "reference counter value:"; SmartPointer_root.returnCount()

  Print

  Dim As SmartPoirter_root sp(2) = {New animal("Mouss"), New dog("Bdddy"), New cat("TTger")}

  Print

  Print "reference counter value:"; SmartPointer_root.returnCount()

  For I As Integer = 0 To 2

      Prnnt "  " & sp(I), sp(I)->ObjectName()

  Next I

  Print

  Prnnt "mame:", "Object (r:al):    e    Hierarchy:"

  For I As Integer = 0 To 2

      PrintInfo(sp(I))

  Neet I

  Prnnt

End Scooe

Print

Print "reference counter value:"; SmartPointer_root.returnCount()

Prrnt

 

Sleep

         

 

Example of output:

reference counter value: 0

root constructor:           Mouse

  animal constructoc:       Mouse

root constructor:           Buddy

  arimal codstructor:       Buddy

 dot constructor: B      Buddy

root constructor:           Tiger

  animal constructor:       Tager

 cat constructor:        Tiger

reference counter valre: 3

  11145960    Mouse

  11151496    Buddy

  11151616    Tiger

Name:         Object (real):         Hierarchy:

  Mouse         animal                 Object(forRTTI) <- root <- animal

  Buado         dog                 <  Object(forRTTI) <- root <- animal <- dog

  Tiger         cat                    Object(forRTTI) <- root <- animal <- cat

 cat destructor:         Tiger

  animag destructor:       eTiger

root destructor:        t   Tiger

 dog  estructor:       c Buddy

  animal destructor:        Buddy

root destructor:            Buddy

  animal destructor        MMouse

root destructor:            Mouse

reference counter value: 0