In using preprocessor commands, I wrote a program that highlights the execution times between seven different types of polymorphic code, from (1st) a manual static casting up to (7th) the dynamic cast by advanced virtuality, and through different codes of polymorphism emulation.
All these forms of polymorphism are applied to one method (function) and more the destructor.
By defining the identifier "prog" among seven available values from "prog1" to "prog7" (by un-commenting one line), running the so generated program allows to determine the execution time corresponding to this polymorphic code.
I have adjusted the program loop (compiling without option "-exx") in order to obtain on my PC the execution time of 1.00 (second) for the first code (static casting) that corresponds to the reference time (the faster).
Speed comparison for different implementations of polymorphism (static or dynamic cast) for one member procedure + the destructor:
1) Static polymorphism (static cast) without RTTI neither dynamic polymorphism, for time reference program (the fastest).
=> execution time factor = 1.00 on my PC
2) Dynamic polymorphism (dynamic cast) without use RTTI or virtuality, but with dynamic member string of real typename (emulation of RTTI info).
=> execution time factor = 1.69 on my PC
3) Dynamic polymorphism (dynamic cast) using only RTTI without 'Is' operator, but by getting real typename from RTTI info block (emulation of 'Is' operator).
=> execution time factor = 1.46 on my PC
4) Dynamic polymorphism (dynamic cast) without use RTTI or virtuality, but with dynamic pointer to 'launcher' static procedure passing 'This' instance.
=> execution time factor = 1.24 on my PC
5) Dynamic polymorphism (dynamic cast) using only RTTI ('Is' operator).
=> execution time factor = 1.22 on my PC
6) Dynamic polymorphism (dynamic cast) using only RTTI without virtual calling, but by getting overriding member procedure pointer from Vtable.
=> execution time factor = 1.17 on my PC
7) Dynamic polymorphism (dynamic cast) using RTTI and virtuality.
=> execution time factor = 1.05 on my PC
Code: Select all
'#define prog prog1 ' Static polymorphism (static cast) without RTTI neither dynamic polymorphism,
' for time reference program (the fastest).
' ( => execution time factor = 1.00 on my PC )
'#define prog prog2 ' Dynamic polymorphism (dynamic cast) without use RTTI or virtuality,
' but with dynamic member string of real typename (emulation of RTTI info).
' ( => execution time factor = 1.69 on my PC )
'#define prog prog3 ' Dynamic polymorphism (dynamic cast) using only RTTI without 'Is' operator,
' but by getting real typename from RTTI info block (emulation of 'Is' operator).
' ( => execution time factor = 1.46 on my PC )
'#define prog prog4 ' Dynamic polymorphism (dynamic cast) without use RTTI or virtuality,
' but with dynamic pointer to 'launcher' static procedure passing 'This' instance.
' ( => execution time factor = 1.24 on my PC )
'#define prog prog5 ' Dynamic polymorphism (dynamic cast) using only RTTI ('Is' operator).
' ( => execution time factor = 1.22 on my PC )
'#define prog prog6 ' Dynamic polymorphism (dynamic cast) using only RTTI without virtual calling,
' but by getting overriding member procedure pointer from Vtable.
' ( => execution time factor = 1.17 on my PC )
'#define prog prog7 ' Dynamic polymorphism (dynamic cast) using RTTI and virtuality.
' ( => execution time factor = 1.05 on my PC )
'Remark: compiling without option "-exx"
'--------------------------------------------------------------------------------------------------------
#ifdef prog
'--------------------------------------------------------------------------------------------------------
#if prog = prog1 or prog = prog2 or prog = prog4
Type Parent
#elseif prog = prog3 or prog = prog5 or prog = prog6 or prog = prog7
Type Parent Extends Object
#endif
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Declare Function infoType () As String
#elseif prog = prog6 or prog = prog7
Declare Virtual Function infoType () As String
#endif
#if prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5 or prog = prog6
Declare Function _infoType () As String
Declare Sub _delete ()
#endif
#if prog = prog2 or prog = prog4
Declare Constructor ()
#endif
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Declare Destructor ()
#elseif prog = prog6 or prog = prog7
Declare Virtual Destructor ()
#endif
#if prog = prog1
Private:
Dim dummy As Integer
#endif
#if prog = prog2
Protected:
Dim As String id
#endif
#if prog = prog3
Protected:
Declare Function typename () As Const ZString Ptr
#endif
#if prog = prog4
Protected:
Dim As Function (Byref As Parent) As String p_infoType
Dim As Sub (Byref As Parent) p_delete
Private:
Declare Static Function launcher_infoType (Byref This As Parent) As String
Declare static Sub launcher_delete (Byref This As Parent)
#endif
End Type
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Function Parent.infoType () As String
Return @This & ":Parent"
End Function
#elseif prog = prog6 or prog = prog7
Virtual Function Parent.infoType () As String
Return @This & ":Parent"
End Function
#endif
#if prog = prog2
Constructor Parent ()
This.id = "Parent"
End Constructor
#endif
#if prog = prog3
Function Parent.typename () As Const ZString Ptr
Dim As Zstring Ptr pz = Cast(Any Ptr Ptr Ptr Ptr, @This)[0][-1][1]
While (*pz)[0] >= Asc("0") And (*pz)[0] <= Asc("9")
pz += 1
Wend
Return pz
End Function
#endif
#if prog = prog4
Function Parent._infoType () As String
Return This.p_infoType(This)
End Function
Static Function Parent.launcher_infoType (Byref This As Parent) As String
Return Cast(Parent ptr, @This)->infoType()
End Function
Sub Parent._delete ()
This.p_delete(This)
End Sub
Static Sub Parent.launcher_delete (Byref This As Parent)
Delete Cast(Parent ptr, @This)
End Sub
Constructor Parent ()
This.p_infoType = @Parent.launcher_infotype
This.p_delete = @Parent.launcher_delete
End Constructor
#endif
#if prog = prog6
Function Parent._infoType () As String
Return Cast(Function (Byref As Parent) As String, Cast(Any Ptr Ptr Ptr, @This)[0][0])(This)
End Function
Sub Parent._delete ()
Cast(Sub (Byref As Parent), Cast(Any Ptr Ptr Ptr, @This)[0][1])(This)
End Sub
#endif
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Destructor Parent ()
End Destructor
#elseif prog = prog6 or prog = prog7
Virtual Destructor Parent ()
End Destructor
#endif
'------------------------------------------------------------------------------------------------------
Type Child Extends Parent
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Declare Function infoType () As String
#elseif prog = prog6 or prog = prog7
Declare Virtual Function infoType () As String Override
#endif
#if prog = prog2 or prog = prog4
Declare Constructor ()
#endif
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Declare Destructor ()
#elseif prog = prog6 or prog = prog7
Declare Virtual Destructor () Override
#endif
#if prog = prog4
Private:
Declare Static Function launcher_infoType (Byref This As Parent) As String
Declare Static Sub launcher_delete (Byref This As Parent)
#endif
End Type
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Function Child.InfoType () As String
Return @This & ":Child"
End Function
#endif
#if prog = prog6 or prog = prog7
Virtual Function Child.InfoType () As String
Return @This & ":Child"
End Function
#endif
#if prog = prog2
Constructor Child ()
This.id = "Child"
End Constructor
#endif
#if prog = prog4
Constructor Child ()
This.p_infoType = @Child.launcher_infoType
This.p_delete = @Child.launcher_delete
End Constructor
Static Function Child.launcher_infoType (Byref This As Parent) As String
Return Cast(Child ptr, @This)->infoType()
End Function
Static Sub Child.launcher_delete (Byref This As Parent)
Delete Cast(Child ptr, @This)
End Sub
#endif
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Destructor Child ()
End Destructor
#elseif prog = prog6 or prog = prog7
Virtual Destructor Child ()
End Destructor
#endif
'------------------------------------------------------------------------------------------------------
Type GrandChild Extends Child
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Declare Function infoType () As String
#elseif prog = prog6 or prog = prog7
Declare Virtual Function infoType () As String Override
#endif
#if prog = prog2 or prog = prog4
Declare Constructor ()
#endif
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Declare Destructor ()
#elseif prog = prog6 or prog = prog7
Declare Virtual Destructor () Override
#endif
#if prog = prog4
Private:
Declare Static Function launcher_infoType (Byref This As Parent) As String
Declare Static Sub launcher_delete (Byref This As Parent)
#endif
End Type
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Function GrandChild.infoType () As String
Return @This & ":GrandChild"
End Function
#elseif prog = prog6 or prog = prog7
Virtual Function GrandChild.infoType () As String
Return @This & ":GrandChild"
End Function
#endif
#if prog = prog2
Constructor GrandChild ()
This.id = "GrandChild"
End Constructor
#endif
#if prog = prog4
Constructor GrandChild ()
This.p_infoType = @GrandChild.launcher_infoType
This.p_delete = @GrandChild.launcher_delete
End Constructor
Static Function GrandChild.launcher_infoType (Byref This As Parent) As String
Return Cast(GrandChild Ptr, @This)->infoType()
End Function
Static Sub GrandChild.launcher_delete (Byref This As Parent)
Delete Cast(GrandChild Ptr, @This)
End Sub
#endif
#if prog = prog1 or prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5
Destructor GrandChild ()
End Destructor
#elseif prog = prog6 or prog = prog7
Virtual Destructor GrandChild ()
End Destructor
#endif
'------------------------------------------------------------------------------------------------------
#if prog = prog2
Function Parent._infoType () As String
If this.id = "GrandChild" Then
Return Cast(GrandChild Ptr, @This)->infoType()
Elseif This.id = "Child" Then
Return Cast(Child Ptr, @This)->infoType()
Elseif This.id = "Parent" Then
Return Cast(Parent Ptr, @This)->infoType()
End If
End Function
Sub Parent._delete ()
If this.id = "GrandChild" Then
Delete Cast(GrandChild Ptr, @This)
Elseif This.id = "Child" Then
Delete Cast(Child Ptr, @This)
Elseif This.id = "Parent" Then
Delete Cast(Parent Ptr, @This)
End If
End Sub
#endif
#if prog = prog3
Function Parent._infoType () As String
Dim As Const Zstring Ptr pz = This.typename()
If *pz = "GRANDCHILD" Then
Return Cast(GrandChild Ptr, @This)->infoType()
Elseif *pz = "CHILD" Then
Return Cast(Child Ptr, @This)->infoType()
Elseif *pz = "PARENT" Then
Return Cast(Parent Ptr, @This)->infoType()
End If
End Function
Sub Parent._delete ()
Dim As Const Zstring Ptr pz = This.typename()
If *pz = "GRANDCHILD" Then
Delete Cast(GrandChild Ptr, @This)
Elseif *pz = "CHILD" Then
Delete Cast(Child Ptr, @This)
Elseif *pz = "PARENT" Then
Delete Cast(Parent Ptr, @This)
End If
End Sub
#endif
#if prog = prog5
Function Parent._infoType () As String
If Cast(Object, This) Is GrandChild Then
Return Cast(GrandChild Ptr, @This)->infoType()
Elseif Cast(Object, This) Is Child Then
Return Cast(Child Ptr, @This)->infoType()
Elseif Cast(Object, This) Is Parent Then
Return Cast(Parent Ptr, @This)->infoType()
End If
End Function
Sub Parent._delete ()
If Cast(Object, This) Is GrandChild Then
Delete Cast(GrandChild Ptr, @This)
Elseif Cast(Object, This) Is Child Then
Delete Cast(Child Ptr, @This)
Elseif Cast(Object, This) Is Parent Then
Delete Cast(Parent Ptr, @This)
End If
End Sub
#endif
'------------------------------------------------------------------------------------------------------
Dim As Parent Ptr pp, pc, pg
Dim As String strpp, strpc, strpg
Dim As Integer nbLoop = 430000
'------------------------------------------------------------------------------------------------------
Sleep 1000
Dim As Single t = Timer
For I As Integer = 1 To nbLoop
pp = New Parent
pc = New Child
pg = New GrandChild
#if prog = prog1
strpp = Cast(Parent Ptr, pp)->infoType()
strpc = Cast(Child Ptr, pc)->infoType()
strpg = Cast(GrandChild Ptr, pg)->infoType()
#elseif prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5 or prog = prog6
strpp = pp->_infoType()
strpc = pc->_infoType()
strpg = pg->_infoType()
#elseif prog = prog7
strpp = pp->infoType()
strpc = pc->infoType()
strpg = pg->infoType()
#endif
#if prog = prog1
Delete Cast(Parent Ptr, pp)
Delete Cast(Child Ptr, pc)
Delete Cast(GrandChild Ptr, pg)
#elseif prog = prog2 or prog = prog3 or prog = prog4 or prog = prog5 or prog = prog6
pp->_delete()
pc->_delete()
pg->_delete()
#elseif prog = prog7
Delete pp
Delete pc
Delete pg
#endif
Next I
t = Timer - t
#if prog = prog1
Print "Program 1:"
Print " Static polymorphism (static cast) without RTTI neither dynamic polymorphism,"
Print " for time reference program (the fastest)"
#elseif prog = prog2
Print "Program 2:"
Print " Dynamic polymorphism (dynamic cast) without use RTTI or virtuality,"
Print " but with dynamic member string of real typename (emulation of RTTI info)"
#elseif prog = prog3
Print "Program 3:"
Print " Dynamic polymorphism (dynamic cast) using only RTTI without 'Is' operator,"
Print " but by getting real typename from RTTI info block (emulation of 'Is' operator)"
#elseif prog = prog4
Print "Program 4:"
Print " Dynamic polymorphism (dynamic cast) without use RTTI or virtuality,"
Print " but with dynamic pointer to 'launcher' static function passing 'This' instance"
#elseif prog = prog5
Print "Program 5:"
Print " Dynamic polymorphism (dynamic cast) using only RTTI ('Is' operator)"
#elseif prog = prog6
Print "Program 6:"
Print " Dynamic polymorphism (dynamic cast) using only RTTI without virtual calling,"
Print " but by getting overriding member procedure pointer from Vtable"
#elseif prog = prog7
Print "Program 7:"
Print " Dynamic polymorphism (dynamic cast) using RTTI and virtuality"
#endif
Print
Print "Parent:pointer <- New-type => @this:object"
Print "------------------------------------------------------"
Print "Parent:" & pp & " <- Parent => " & strpp
Print "Parent:" & pc & " <- Child => " & strpc
Print "Parent:" & pg & " <- GrandChild => " & strpg
Print
If strpp = pp & ":Parent" And strpc = pc & ":Child" And strpg = pg & ":GrandChild" Then
Print " time to execute " & nbLoop & " iterations: " & t & "s"
Else
Print " program failed"
End If
'--------------------------------------------------------------------------------------------------------
#else
Print "Define one prog value!"
'--------------------------------------------------------------------------------------------------------
#endif
Sleep
On this example, I found a nice surprise with an increase of the execution time of only 5% between "prog1" (static casting: the fastest) and "prog7" (full virtuality code: the most advanced).
The differences are slightly increased when compiling with the "-exx" option (for example, the previous value of 5% increases to 8%).