OBJECT built-in and RTTI info
How the OBJECT built-in implements the capacity of inheritance polymorphism and the Run-Time Type Information for identification.
Preamble:
The Object built-in type provides to all types derived (using the Extends declaration):
- The ability to redefine a method (using the Abstract / Virtual keywords) in a derived-type (sub-type) inheriting from a base-type (super-type). It is then possible to call the method of an object without worrying about its intrinsic type: it is the inheritance polymorphism (sub-type polymorphism).
- The capacity of determining the real type of an object at run-time, which can be different of its at compile-time. The operator Is (Run-Time Type Information) uses it to check if an object is compatible to a type derived from its compile-time type, because RTTI provides not only the run-time typename of the object but also all names of its different base-types, up to the Object built-in type.
Table of Contents- The capacity of determining the real type of an object at run-time, which can be different of its at compile-time. The operator Is (Run-Time Type Information) uses it to check if an object is compatible to a type derived from its compile-time type, because RTTI provides not only the run-time typename of the object but also all names of its different base-types, up to the Object built-in type.
1. Mechanism under the hood for inheritance polymorphism and RTTI info
The abstract/virtual member procedures are implemented using virtual procedure tables (vtbl). vtbl is, simply explained, a table of static procedures pointers.
The compiler fills a vtbl for each polymorphic type, i.e. a type defining at least an abstract/virtual procedure or a type derived from the former.
vtbl contains entries for all abstract/virtual procedures available in the type, including the abstract/virtual procedures defined in upper level of inheritance hierarchy (for abstract procedure not still implemented, a null pointer is set in the vtbl).
Each vtbl contains the correct addresses of procedures for each abstract/virtual procedure in corresponding type. Here correct means the address of the corresponding procedure of the most derived-type that defines/overrides that procedure:
The abstract/virtual procedure call is converted by compiler to something else by using the proper vtbl addressed by the vptr value (located at offset 0 in the instance data):
The compiler fills a vtbl for each polymorphic type, i.e. a type defining at least an abstract/virtual procedure or a type derived from the former.
vtbl contains entries for all abstract/virtual procedures available in the type, including the abstract/virtual procedures defined in upper level of inheritance hierarchy (for abstract procedure not still implemented, a null pointer is set in the vtbl).
Each vtbl contains the correct addresses of procedures for each abstract/virtual procedure in corresponding type. Here correct means the address of the corresponding procedure of the most derived-type that defines/overrides that procedure:
- When the type is instantiated, the instance will contain a pointer (vptr) to the virtual procedure table (vtbl) of the instantiated type.
- When an object of a derived-type is referenced within a pointer/reference of base-type, then abstract/virtual procedure feature really performs. The call of an abstract/virtual procedure is somehow translated at run-time and the corresponding procedure from the virtual procedure table of the type of underlying object (not of the pointer/reference type) is chosen.
- Thus, what procedure is called depends on what the real type of object the pointer/reference points to, which can't be known at compile-time, that is why the abstract/virtual procedure call is decided at run-time.
Therefore, the abstract/virtual procedure call (by means of a pointer or a reference) is not an ordinary call and has a little performance overhead, which may turn into a huge if we have numerous calls.- When an object of a derived-type is referenced within a pointer/reference of base-type, then abstract/virtual procedure feature really performs. The call of an abstract/virtual procedure is somehow translated at run-time and the corresponding procedure from the virtual procedure table of the type of underlying object (not of the pointer/reference type) is chosen.
- Thus, what procedure is called depends on what the real type of object the pointer/reference points to, which can't be known at compile-time, that is why the abstract/virtual procedure call is decided at run-time.
The abstract/virtual procedure call is converted by compiler to something else by using the proper vtbl addressed by the vptr value (located at offset 0 in the instance data):
Let be 'method1()', 'method2()', 'method3()' the first three abstract or virtual member procedures declared in an inheritance type structure, and 'pt' a based pointer to a derived object:
For the vptr value setting:
pt->method1()
pt->method2()
pt->method3()
are about translated by the compiler into respectively:pt->method2()
pt->method3()
Cptr(Sub (Byref As typename), Cptr(Any Ptr Ptr Ptr, pt)[0][0])(*pt)
Cptr(Sub (Byref As typename), Cptr(Any Ptr Ptr Ptr, pt)[0][1])(*pt)
Cptr(Sub (Byref As typename), Cptr(Any Ptr Ptr Ptr, pt)[0][2])(*pt)
Cptr(Sub (Byref As typename), Cptr(Any Ptr Ptr Ptr, pt)[0][1])(*pt)
Cptr(Sub (Byref As typename), Cptr(Any Ptr Ptr Ptr, pt)[0][2])(*pt)
- The first indirection [0] allows to access to the value of the vptr from the address of the instance. This value correspond to the address of the vtbl.
- The second indirection [0] or [1] or [2] allows to access in the vtbl to the static address of the virtual procedures 'method1()' or 'method2()' or 'method3()' respectively (in the declaration order of the abstract or virtual procedures of the Type structure).
- The second indirection [0] or [1] or [2] allows to access in the vtbl to the static address of the virtual procedures 'method1()' or 'method2()' or 'method3()' respectively (in the declaration order of the abstract or virtual procedures of the Type structure).
- The compiler generates some extra code in the constructor of each type (from the base-type up to the instantiated type), which it adds before the user code. Even if the user does not define a constructor, the compiler generates a default one, and the initialization of vptr is there (from the vtbl address of the base-type up to the one of the instantiated type). So each time an object of a polymorphic type is created, vptr is correctly initialized and finally points to the vtbl of that instantiated type.
- At the end, when the object is destructed, the destructors are called in the reverse order (from the instantiated type up to the base-type). The compiler also generates some extra code in the destructor of each type, which it adds before the user code. Even if the user does not define a destructor, the compiler generates a default one, and the de-initialization of vptr is there (from the vtbl address of the instantiated type up to the one of the base-type).
- This initialization/de-initialization of the vptr value by step is mandatory so that the user code in each constructor/destructor can call the polymorphic procedures at the correct type level during the successive steps of construction/destruction.
The built-in Object type also provides the RTTI (Run-Time Type Information) capacity for all types derived from it using the Extends declaration:- At the end, when the object is destructed, the destructors are called in the reverse order (from the instantiated type up to the base-type). The compiler also generates some extra code in the destructor of each type, which it adds before the user code. Even if the user does not define a destructor, the compiler generates a default one, and the de-initialization of vptr is there (from the vtbl address of the instantiated type up to the one of the base-type).
- This initialization/de-initialization of the vptr value by step is mandatory so that the user code in each constructor/destructor can call the polymorphic procedures at the correct type level during the successive steps of construction/destruction.
- The RTTI capacity allows to determine the real type of an object at run-time, which can be different of its at compile-time.
- The operator Is (rtti) uses it to check if an object is compatible to a type derived from its compile-time type, because RTTI provides not only the real runtime type-name of the object but also all type-names of its base types, up to the Object built-in type.
- Nevertheless these type-names stored by RTTI (referenced by a specific pointer in the vtbl) are mangled names inaccessible directly from a FreeBASIC keyword.
How are chained the entities: object instance, vptr, vtbl (vtable), and RTTI info:- The operator Is (rtti) uses it to check if an object is compatible to a type derived from its compile-time type, because RTTI provides not only the real runtime type-name of the object but also all type-names of its base types, up to the Object built-in type.
- Nevertheless these type-names stored by RTTI (referenced by a specific pointer in the vtbl) are mangled names inaccessible directly from a FreeBASIC keyword.
- Instance -> Vptr -> Vtbl -> RTTI info chaining:
- For any type derived (directly or indirectly) from the Object built-in type, a hidden pointer vptr is added at beginning (located at offset 0) of its data fields (own or inherited). This vptr points to the virtual table vtbl of the considered type.
- The vtbl contains the list of the addresses of all abstract/virtual procedures (from the offset 0). The vtbl also contains (located at offset -1) a pointer to the Run Time Type Information (RTTI) info block of the considered type.
- The RTTI info block contains (located at offset +1) a pointer to the mangled-typename of the considered type (ascii characters). The RTTI info block also contains (located at offset +2) a pointer to the RTTI info block of its Base. All RTTI info blocks for up-hierarchy are so chained.
- Instance -> Vptr -> Vtbl -> RTTI info diagram:- The vtbl contains the list of the addresses of all abstract/virtual procedures (from the offset 0). The vtbl also contains (located at offset -1) a pointer to the Run Time Type Information (RTTI) info block of the considered type.
- The RTTI info block contains (located at offset +1) a pointer to the mangled-typename of the considered type (ascii characters). The RTTI info block also contains (located at offset +2) a pointer to the RTTI info block of its Base. All RTTI info blocks for up-hierarchy are so chained.
' vtbl (vtable) ' .-------------------. ' [-2]| reserved (0) | RTTI info Mangled Typename ' |-------------------| .-----------------------. .---------------. ' Instance of UDT [-1]| Ptr to RTTI info |--->[0]| reserved (0) | |Typename string| ' .-------------------. |-------------------| |-----------------------| | with | ' [0]| vptr: Ptr to vtbl |--->[0]|Ptr to virt proc #1| [+1]|Ptr to Mangled Typename|--->[0]| length (ASCII)| ' |-------------------| |-------------------| |-----------------------| | & | ' |UDT member field #a| [+1]|Ptr to virt proc #2| [+2]| Ptr to Base RTTI info |---. | name (ASCII) | ' |-------------------| |-------------------| |_______________________| | | for | ' |UDT member field #b| [+2]|Ptr to virt proc #3| ________________________________| |each component | ' |-------------------| :- - - - - - - - - -: | |_______________| ' |UDT member field #c| : : | Base RTTI info ' :- - - - - - - - - -: : : | .----------------------------. ' : : |___________________| '--->[0]| reserved (0) | ' : : |----------------------------| ' |___________________| [+1]|Ptr to Mangled Base Typename|---> ' |----------------------------| ' [+2]| Ptr to Base.Base RTTI info |---. ' |____________________________| | ' | ' V
2. Inheritance polymorphism mechanism demonstrated by both true operating and faithful emulation
In the below proposed example, the polymorphic part is broken down to better bring out all the elements necessary for the mechanics of polymorphism.
Example of inheritance polymorphism, true operating: 'Animal type collection'
Example of inheritance polymorphism, true operating: 'Animal type collection'
The generic base-type chosen is any 'animal' (abstraction).
The specialized derived-types are a 'dog', a 'cat', and a 'bird' (each defining a non-static string member containing its type-name).
The abstract procedures declared in the generic base-type, and which must be defined in each specialized derived-type, are:
The specialized derived-types are a 'dog', a 'cat', and a 'bird' (each defining a non-static string member containing its type-name).
The abstract procedures declared in the generic base-type, and which must be defined in each specialized derived-type, are:
- 'addr_override_fct()': returns the instance address,
- 'speak_override_fct()': returns the way of speaking,
- 'type_override_sub()': prints the type-name (from a string member with initialyzer).
- 'speak_override_fct()': returns the way of speaking,
- 'type_override_sub()': prints the type-name (from a string member with initialyzer).
- 'animal' type declaration (generic base-type):
- 'dog', 'cat', 'bird' types declarations (specialized derived-types):
- Full code of example:
- Three public abstract procedures ('addr_override_fct()', 'speak_override_fct()', 'type_override_sub()') are declared (but without any body defining them).
- This base-type is non-instantiable, because containing an abstract procedure at least.
- This base-type is non-instantiable, because containing an abstract procedure at least.
'Base-type animal: Type animal Extends Object Public: Declare Abstract Function addr_override_fct () As animal Ptr Declare Abstract Function speak_override_fct () As String Declare Abstract Sub type_override_sub () End Type
- For each derived-type, the three same public procedures ('addr_override_fct()', 'speak_override_fct()', 'type_override_sub()') are declared virtual, and their bodies are specialized for each derived-type.
- For each derived-type, a non-static string member initialized with its type-name.
- Each derived-type is instantiable, because implementing all abstract procedures declared in its base.
- For each derived-type, a non-static string member initialized with its type-name.
- Each derived-type is instantiable, because implementing all abstract procedures declared in its base.
'Derived-type dog: Type dog Extends animal Public: Declare Virtual Function addr_override_fct () As animal Ptr Override Declare Virtual Function speak_override_fct () As String Override Declare Virtual Sub type_override_sub () Override Private: Dim As String animal_type = "dog" End Type
'Derived-type cat: Type cat Extends animal Public: Declare Virtual Function addr_override_fct () As animal Ptr Override Declare Virtual Function speak_override_fct () As String Override Declare Virtual Sub type_override_sub () Override Private: Dim As String animal_type = "cat" End Type
'Derived-type bird: Type bird Extends animal Public: Declare Virtual Function addr_override_fct () As animal Ptr Override Declare Virtual Function speak_override_fct () As String Override Declare Virtual Sub type_override_sub () Override Private: Dim As String animal_type = "bird" End Type
- To be able to trigger polymorphism, a base-type pointer array ('animal_list') is declared then initialized with instances of different derived-types (a dog, a cat, a bird), in order to constitute a collection of objects from different types (but all having a common base-type).
- So, the same compiled code line, put in a loop (iterator 'I'), processes all instances from different types ('animal_list(I)->addr_override_fct()', 'animal_list(I)->speak_override_fct()', 'animal_list(I)->type_override_sub()'), because the polymorphism mechanic allows to call each specialized procedure at run-time.
- So, the same compiled code line, put in a loop (iterator 'I'), processes all instances from different types ('animal_list(I)->addr_override_fct()', 'animal_list(I)->speak_override_fct()', 'animal_list(I)->type_override_sub()'), because the polymorphism mechanic allows to call each specialized procedure at run-time.
'Base-type animal:
Type animal Extends Object
Public:
Declare Abstract Function addr_override_fct () As animal Ptr
Declare Abstract Function speak_override_fct () As String
Declare Abstract Sub type_override_sub ()
End Type
'Derived-type dog:
Type dog Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "dog"
End Type
'override_sub procedures for dog object:
Virtual Function dog.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function dog.speak_override_fct () As String
Return "Woof!"
End Function
Virtual Sub dog.type_override_sub ()
Print This.animal_type
End Sub
'Derived-type cat:
Type cat Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "cat"
End Type
'override_sub mehods for cat object:
Virtual Function cat.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function cat.speak_override_fct () As String
Return "Meow!"
End Function
Virtual Sub cat.type_override_sub ()
Print This.animal_type
End Sub
'Derived-type bird:
Type bird Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "bird"
End Type
'override_sub mehods for bird object:
Virtual Function bird.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function bird.speak_override_fct () As String
Return "Cheep!"
End Function
Virtual Sub bird.type_override_sub ()
Print This.animal_type
End Sub
'Create a dog and cat and bird dynamic instances referred through an animal pointer list:
Dim As dog Ptr p_my_dog = New dog
Dim As cat Ptr p_my_cat = New cat
Dim As bird Ptr p_my_bird = New bird
Dim As animal Ptr animal_list (1 To ...) = {p_my_dog, p_my_cat, p_my_bird}
'Have the animals speak and eat:
Print "INHERITANCE POLYMORPHISM", "@object", "speak", "type"
Print " true operating"
For I As Integer = LBound(animal_list) To UBound(animal_list)
Print " animal #" & I & ":",
Print animal_list(I)->addr_override_fct(), 'real polymorphism
Print animal_list(I)->speak_override_fct(), 'real polymorphism
animal_list(I)->type_override_sub() 'real polymorphism
Next I
Sleep
Delete p_my_dog
Delete p_my_cat
Delete p_my_bird
Ouput:Type animal Extends Object
Public:
Declare Abstract Function addr_override_fct () As animal Ptr
Declare Abstract Function speak_override_fct () As String
Declare Abstract Sub type_override_sub ()
End Type
'Derived-type dog:
Type dog Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "dog"
End Type
'override_sub procedures for dog object:
Virtual Function dog.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function dog.speak_override_fct () As String
Return "Woof!"
End Function
Virtual Sub dog.type_override_sub ()
Print This.animal_type
End Sub
'Derived-type cat:
Type cat Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "cat"
End Type
'override_sub mehods for cat object:
Virtual Function cat.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function cat.speak_override_fct () As String
Return "Meow!"
End Function
Virtual Sub cat.type_override_sub ()
Print This.animal_type
End Sub
'Derived-type bird:
Type bird Extends animal
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
Private:
Dim As String animal_type = "bird"
End Type
'override_sub mehods for bird object:
Virtual Function bird.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function bird.speak_override_fct () As String
Return "Cheep!"
End Function
Virtual Sub bird.type_override_sub ()
Print This.animal_type
End Sub
'Create a dog and cat and bird dynamic instances referred through an animal pointer list:
Dim As dog Ptr p_my_dog = New dog
Dim As cat Ptr p_my_cat = New cat
Dim As bird Ptr p_my_bird = New bird
Dim As animal Ptr animal_list (1 To ...) = {p_my_dog, p_my_cat, p_my_bird}
'Have the animals speak and eat:
Print "INHERITANCE POLYMORPHISM", "@object", "speak", "type"
Print " true operating"
For I As Integer = LBound(animal_list) To UBound(animal_list)
Print " animal #" & I & ":",
Print animal_list(I)->addr_override_fct(), 'real polymorphism
Print animal_list(I)->speak_override_fct(), 'real polymorphism
animal_list(I)->type_override_sub() 'real polymorphism
Next I
Sleep
Delete p_my_dog
Delete p_my_cat
Delete p_my_bird
INHERITANCE POLYMORPHISM @object speak type true operating animal #1: 11479616 Woof! dog animal #2: 11479688 Meow! cat animal #3: 11479760 Cheep! bird
This following emulation of sub-type polymorphism is very close to the real operating:
- A static procedure pointer table 'callback_table()' is defined for each derived-type to emulate the vtbl (an instance reference will be passed as first parameter to each static procedure to emulate the hidden 'This' reference passed to any non-static member procedure).
- At the base-type level, a non static pointer 'callback_ptr' is allocated for any derived-type instance to emulate the vptr (its value, initialized by the constructor, will depend on what derived-type is constructed: address of the following described table).
- At the base-type level, each abstract procedure is replaced by a member procedure calling the proper derived procedure through the 'callback_ptr' / 'callback_table(I)' ('I' being the index inside the table corresponding to this procedure).
'Derived-type dog: Type dog Extends animal Private: Static As Any Ptr callback_table(0 To 2) Public: Declare Static Function addr_callback_fct (Byref As dog) As animal Ptr Declare Static Function speak_callback_fct (Byref As dog) As String Declare Static Sub type_callback_sub (Byref As dog) Declare Constructor () Private: Dim As String animal_type = "dog" End Type Static As Any Ptr dog.callback_table(0 To 2) = {@dog.addr_callback_fct, @dog.speak_callback_fct, @dog.type_callback_sub}
'Derived-type cat: Type cat Extends animal Private: Static As Any Ptr callback_table(0 To 2) Public: Declare Static Function addr_callback_fct (Byref As cat) As animal Ptr Declare Static Function speak_callback_fct (Byref As cat) As String Declare Static Sub type_callback_sub (Byref As cat) Declare Constructor () Private: Dim As String animal_type = "cat" End Type Static As Any Ptr cat.callback_table(0 To 2) = {@cat.addr_callback_fct, @cat.speak_callback_fct, @cat.type_callback_sub}
'Derived-type bird: Type bird Extends animal Private: Static As Any Ptr callback_table(0 To 2) Public: Declare Static Function addr_callback_fct (Byref As bird) As animal Ptr Declare Static Function speak_callback_fct (Byref As bird) As String Declare Static Sub type_callback_sub (Byref As bird) Declare Constructor () Private: Dim As String animal_type = "bird" End Type Static As Any Ptr bird.callback_table(0 To 2) = {@bird.addr_callback_fct, @bird.speak_callback_fct, @bird.type_callback_sub}
- At the base-type level, a non static pointer 'callback_ptr' is allocated for any derived-type instance to emulate the vptr (its value, initialized by the constructor, will depend on what derived-type is constructed: address of the following described table).
- At the base-type level, each abstract procedure is replaced by a member procedure calling the proper derived procedure through the 'callback_ptr' / 'callback_table(I)' ('I' being the index inside the table corresponding to this procedure).
'Base-type animal: Type animal Protected: Dim As Any Ptr Ptr callback_ptr Public: Declare Function addr_callback_fct () As animal Ptr Declare Function speak_callback_fct () As String Declare Sub type_callback_sub () End Type Function animal.addr_callback_fct () As animal Ptr Return Cptr(Function (Byref As animal) As animal Ptr, This.callback_ptr[0])(This) End Function Function animal.speak_callback_fct () As String Return Cptr(Function (Byref As animal) As String, This.callback_ptr[1])(This) End Function Sub animal.type_callback_sub () Cptr(Sub (Byref As animal), This.callback_ptr[2])(This) End Sub
- Full code of emulation:
' Emulation of polymorphism is very close to the real operating:
' - a non static pointer is allocated for any derived-type instance to emulate the vptr
' (its value will depend on what derived-type is constructed: address of the following table)
' - a static procedure pointer table is defined for each derived type to emulate the vtable
' (an instance reference is passed as first parameter to each static procedure to emulate the hidden 'This' reference passed to any non-static member procedure)
'Base-type animal:
Type animal
Protected:
Dim As Any Ptr Ptr callback_ptr
Public:
Declare Function addr_callback_fct () As animal Ptr
Declare Function speak_callback_fct () As String
Declare Sub type_callback_sub ()
End Type
Function animal.addr_callback_fct () As animal Ptr
Return CPtr(Function (ByRef As animal) As animal Ptr, This.callback_ptr[0])(This)
End Function
Function animal.speak_callback_fct () As String
Return CPtr(Function (ByRef As animal) As String, This.callback_ptr[1])(This)
End Function
Sub animal.type_callback_sub ()
CPtr(Sub (ByRef As animal), This.callback_ptr[2])(This)
End Sub
'Derived-type dog:
Type dog Extends animal
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As dog) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As dog) As String
Declare Static Sub type_callback_sub (ByRef As dog)
Declare Constructor ()
Private:
Dim As String animal_type = "dog"
End Type
Static As Any Ptr dog.callback_table(0 To 2) = {@dog.addr_callback_fct, @dog.speak_callback_fct, @dog.type_callback_sub}
'callback_sub methods + constructor for dog object:
Static Function dog.addr_callback_fct (ByRef d As dog) As animal Ptr
Return @d
End Function
Static Function dog.speak_callback_fct (ByRef d As dog) As String
Return "Woof!"
End Function
Static Sub dog.type_callback_sub (ByRef d As dog)
Print d.animal_type
End Sub
Constructor dog ()
This.callback_ptr = @callback_table(0)
End Constructor
'Derived-type cat:
Type cat Extends animal
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As cat) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As cat) As String
Declare Static Sub type_callback_sub (ByRef As cat)
Declare Constructor ()
Private:
Dim As String animal_type = "cat"
End Type
Static As Any Ptr cat.callback_table(0 To 2) = {@cat.addr_callback_fct, @cat.speak_callback_fct, @cat.type_callback_sub}
'callback_sub mehods + constructor for cat object:
Static Function cat.addr_callback_fct (ByRef c As cat) As animal Ptr
Return @c
End Function
Static Function cat.speak_callback_fct (ByRef c As cat) As String
Return "Meow!"
End Function
Static Sub cat.type_callback_sub (ByRef c As cat)
Print c.animal_type
End Sub
Constructor cat ()
This.callback_ptr = @callback_table(0)
End Constructor
'Derived-type bird:
Type bird Extends animal
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As bird) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As bird) As String
Declare Static Sub type_callback_sub (ByRef As bird)
Declare Constructor ()
Private:
Dim As String animal_type = "bird"
End Type
Static As Any Ptr bird.callback_table(0 To 2) = {@bird.addr_callback_fct, @bird.speak_callback_fct, @bird.type_callback_sub}
'callback_sub mehods + constructor for bird object:
Static Function bird.addr_callback_fct (ByRef b As bird) As animal Ptr
Return @b
End Function
Static Function bird.speak_callback_fct (ByRef b As bird) As String
Return "Cheep!"
End Function
Static Sub bird.type_callback_sub (ByRef b As bird)
Print b.animal_type
End Sub
Constructor bird ()
This.callback_ptr = @callback_table(0)
End Constructor
'Create a dog and cat and bird dynamic instances referred through an animal pointer list:
Dim As dog Ptr p_my_dog = New dog
Dim As cat Ptr p_my_cat = New cat
Dim As bird Ptr p_my_bird = New bird
Dim As animal Ptr animal_list (1 To ...) = {p_my_dog, p_my_cat, p_my_bird}
'Have the animals speak and eat:
Print "SUB-TYPE POLYMORPHISM", "@object", "speak", "type"
Print " by emulation"
For I As Integer = LBound(animal_list) To UBound(animal_list)
Print " animal #" & I & ":",
Print animal_list(I)->addr_callback_fct(), 'emulated polymorphism
Print animal_list(I)->speak_callback_fct(), 'emulated polymorphism
animal_list(I)->type_callback_sub() 'emulated polymorphism
Next I
Sleep
Delete p_my_dog
Delete p_my_cat
Delete p_my_bird
Output:' - a non static pointer is allocated for any derived-type instance to emulate the vptr
' (its value will depend on what derived-type is constructed: address of the following table)
' - a static procedure pointer table is defined for each derived type to emulate the vtable
' (an instance reference is passed as first parameter to each static procedure to emulate the hidden 'This' reference passed to any non-static member procedure)
'Base-type animal:
Type animal
Protected:
Dim As Any Ptr Ptr callback_ptr
Public:
Declare Function addr_callback_fct () As animal Ptr
Declare Function speak_callback_fct () As String
Declare Sub type_callback_sub ()
End Type
Function animal.addr_callback_fct () As animal Ptr
Return CPtr(Function (ByRef As animal) As animal Ptr, This.callback_ptr[0])(This)
End Function
Function animal.speak_callback_fct () As String
Return CPtr(Function (ByRef As animal) As String, This.callback_ptr[1])(This)
End Function
Sub animal.type_callback_sub ()
CPtr(Sub (ByRef As animal), This.callback_ptr[2])(This)
End Sub
'Derived-type dog:
Type dog Extends animal
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As dog) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As dog) As String
Declare Static Sub type_callback_sub (ByRef As dog)
Declare Constructor ()
Private:
Dim As String animal_type = "dog"
End Type
Static As Any Ptr dog.callback_table(0 To 2) = {@dog.addr_callback_fct, @dog.speak_callback_fct, @dog.type_callback_sub}
'callback_sub methods + constructor for dog object:
Static Function dog.addr_callback_fct (ByRef d As dog) As animal Ptr
Return @d
End Function
Static Function dog.speak_callback_fct (ByRef d As dog) As String
Return "Woof!"
End Function
Static Sub dog.type_callback_sub (ByRef d As dog)
Print d.animal_type
End Sub
Constructor dog ()
This.callback_ptr = @callback_table(0)
End Constructor
'Derived-type cat:
Type cat Extends animal
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As cat) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As cat) As String
Declare Static Sub type_callback_sub (ByRef As cat)
Declare Constructor ()
Private:
Dim As String animal_type = "cat"
End Type
Static As Any Ptr cat.callback_table(0 To 2) = {@cat.addr_callback_fct, @cat.speak_callback_fct, @cat.type_callback_sub}
'callback_sub mehods + constructor for cat object:
Static Function cat.addr_callback_fct (ByRef c As cat) As animal Ptr
Return @c
End Function
Static Function cat.speak_callback_fct (ByRef c As cat) As String
Return "Meow!"
End Function
Static Sub cat.type_callback_sub (ByRef c As cat)
Print c.animal_type
End Sub
Constructor cat ()
This.callback_ptr = @callback_table(0)
End Constructor
'Derived-type bird:
Type bird Extends animal
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As bird) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As bird) As String
Declare Static Sub type_callback_sub (ByRef As bird)
Declare Constructor ()
Private:
Dim As String animal_type = "bird"
End Type
Static As Any Ptr bird.callback_table(0 To 2) = {@bird.addr_callback_fct, @bird.speak_callback_fct, @bird.type_callback_sub}
'callback_sub mehods + constructor for bird object:
Static Function bird.addr_callback_fct (ByRef b As bird) As animal Ptr
Return @b
End Function
Static Function bird.speak_callback_fct (ByRef b As bird) As String
Return "Cheep!"
End Function
Static Sub bird.type_callback_sub (ByRef b As bird)
Print b.animal_type
End Sub
Constructor bird ()
This.callback_ptr = @callback_table(0)
End Constructor
'Create a dog and cat and bird dynamic instances referred through an animal pointer list:
Dim As dog Ptr p_my_dog = New dog
Dim As cat Ptr p_my_cat = New cat
Dim As bird Ptr p_my_bird = New bird
Dim As animal Ptr animal_list (1 To ...) = {p_my_dog, p_my_cat, p_my_bird}
'Have the animals speak and eat:
Print "SUB-TYPE POLYMORPHISM", "@object", "speak", "type"
Print " by emulation"
For I As Integer = LBound(animal_list) To UBound(animal_list)
Print " animal #" & I & ":",
Print animal_list(I)->addr_callback_fct(), 'emulated polymorphism
Print animal_list(I)->speak_callback_fct(), 'emulated polymorphism
animal_list(I)->type_callback_sub() 'emulated polymorphism
Next I
Sleep
Delete p_my_dog
Delete p_my_cat
Delete p_my_bird
SUB-TYPE POLYMORPHISM @object speak type by emulation animal #1: 12462656 Woof! dog animal #2: 12462728 Meow! cat animal #3: 12462800 Cheep! bird
The real code and emulation code are nested in a single code for easier comparison:
' Emulated polymorphism (with explicit callback member procedures)
' and
' True polymorphism (with abstract/virtual member procedures),
' both in an inheritance structure.
'Base-type animal:
Type animal Extends Object 'Extends Object' useful for true polymorphism only
' for true polymorphism:
Public:
Declare Abstract Function addr_override_fct () As animal Ptr
Declare Abstract Function speak_override_fct () As String
Declare Abstract Sub type_override_sub ()
' for polymorphism emulation:
Protected:
Dim As Any Ptr Ptr callback_ptr
Public:
Declare Function addr_callback_fct () As animal Ptr
Declare Function speak_callback_fct () As String
Declare Sub type_callback_sub ()
End Type
' for polymorphism emulation:
Function animal.addr_callback_fct () As animal Ptr
Return CPtr(Function (ByRef As animal) As animal Ptr, This.callback_ptr[0])(This)
End Function
Function animal.speak_callback_fct () As String
Return CPtr(Function (ByRef As animal) As String, This.callback_ptr[1])(This)
End Function
Sub animal.type_callback_sub ()
CPtr(Sub (ByRef As animal), This.callback_ptr[2])(This)
End Sub
'Derived-type dog:
Type dog Extends animal
' for true polymorphism:
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
' for polymorphism emulation:
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As dog) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As dog) As String
Declare Static Sub type_callback_sub (ByRef As dog)
Declare Constructor ()
' for all:
Private:
Dim As String animal_type = "dog"
End Type
' for true polymorphism:
' override_sub methods for dog object:
Virtual Function dog.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function dog.speak_override_fct () As String
Return "Woof!"
End Function
Virtual Sub dog.type_override_sub ()
Print This.animal_type
End Sub
' for polymorphism emulation:
Static As Any Ptr dog.callback_table(0 To 2) = {@dog.addr_callback_fct, @dog.speak_callback_fct, @dog.type_callback_sub}
'callback_sub methods + constructor for dog object:
Static Function dog.addr_callback_fct (ByRef d As dog) As animal Ptr
Return @d
End Function
Static Function dog.speak_callback_fct (ByRef d As dog) As String
Return "Woof!"
End Function
Static Sub dog.type_callback_sub (ByRef d As dog)
Print d.animal_type
End Sub
Constructor dog ()
This.callback_ptr = @callback_table(0)
End Constructor
'Derived-type cat:
Type cat Extends animal
' for true polymorphism:
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
' for polymorphism emulation:
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As cat) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As cat) As String
Declare Static Sub type_callback_sub (ByRef As cat)
Declare Constructor ()
' for all:
Private:
Dim As String animal_type = "cat"
End Type
' for true polymorphism:
' override_sub mehods for cat object:
Virtual Function cat.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function cat.speak_override_fct () As String
Return "Meow!"
End Function
Virtual Sub cat.type_override_sub ()
Print This.animal_type
End Sub
' for polymorphism emulation:
Static As Any Ptr cat.callback_table(0 To 2) = {@cat.addr_callback_fct, @cat.speak_callback_fct, @cat.type_callback_sub}
' callback_sub mehods + constructor for cat object:
Static Function cat.addr_callback_fct (ByRef c As cat) As animal Ptr
Return @c
End Function
Static Function cat.speak_callback_fct (ByRef c As cat) As String
Return "Meow!"
End Function
Static Sub cat.type_callback_sub (ByRef c As cat)
Print c.animal_type
End Sub
Constructor cat ()
This.callback_ptr = @callback_table(0)
End Constructor
'Derived-type bird:
Type bird Extends animal
' for true polymorphism:
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
' for polymorphism emulation:
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As bird) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As bird) As String
Declare Static Sub type_callback_sub (ByRef As bird)
Declare Constructor ()
' for all:
Private:
Dim As String animal_type = "bird"
End Type
' for true polymorphism:
' override_sub mehods for bird object:
Virtual Function bird.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function bird.speak_override_fct () As String
Return "Cheep!"
End Function
Virtual Sub bird.type_override_sub ()
Print This.animal_type
End Sub
' for polymorphism emulation:
Static As Any Ptr bird.callback_table(0 To 2) = {@bird.addr_callback_fct, @bird.speak_callback_fct, @bird.type_callback_sub}
' callback_sub mehods + constructor for bird object:
Static Function bird.addr_callback_fct (ByRef b As bird) As animal Ptr
Return @b
End Function
Static Function bird.speak_callback_fct (ByRef b As bird) As String
Return "Cheep!"
End Function
Static Sub bird.type_callback_sub (ByRef b As bird)
Print b.animal_type
End Sub
Constructor bird ()
This.callback_ptr = @callback_table(0)
End Constructor
'Create a dog and cat and bird dynamic instances referred through an animal pointer list:
Dim As dog Ptr p_my_dog = New dog
Dim As cat Ptr p_my_cat = New cat
Dim As bird Ptr p_my_bird = New bird
Dim As animal Ptr animal_list (1 To ...) = {p_my_dog, p_my_cat, p_my_bird}
'Have the animals speak and eat:
Print "SUB-TYPE POLYMORPHISM", "@object", "speak", "type"
For I As Integer = LBound(animal_list) To UBound(animal_list)
Print " animal #" & I & ":"
' for override_sub:
Print " true operating:",
Print animal_list(I)->addr_override_fct(), 'real polymorphism
Print animal_list(I)->speak_override_fct(), 'real polymorphism
animal_list(I)->type_override_sub() 'real polymorphism
' for polymorphism emulation:
Print " by emulation:",
Print animal_list(I)->addr_callback_fct(), 'emulated polymorphism
Print animal_list(I)->speak_callback_fct(), 'emulated polymorphism
animal_list(I)->type_callback_sub() 'emulated polymorphism
Next I
Sleep
Delete p_my_dog
Delete p_my_cat
Delete p_my_bird
Output:' and
' True polymorphism (with abstract/virtual member procedures),
' both in an inheritance structure.
'Base-type animal:
Type animal Extends Object 'Extends Object' useful for true polymorphism only
' for true polymorphism:
Public:
Declare Abstract Function addr_override_fct () As animal Ptr
Declare Abstract Function speak_override_fct () As String
Declare Abstract Sub type_override_sub ()
' for polymorphism emulation:
Protected:
Dim As Any Ptr Ptr callback_ptr
Public:
Declare Function addr_callback_fct () As animal Ptr
Declare Function speak_callback_fct () As String
Declare Sub type_callback_sub ()
End Type
' for polymorphism emulation:
Function animal.addr_callback_fct () As animal Ptr
Return CPtr(Function (ByRef As animal) As animal Ptr, This.callback_ptr[0])(This)
End Function
Function animal.speak_callback_fct () As String
Return CPtr(Function (ByRef As animal) As String, This.callback_ptr[1])(This)
End Function
Sub animal.type_callback_sub ()
CPtr(Sub (ByRef As animal), This.callback_ptr[2])(This)
End Sub
'Derived-type dog:
Type dog Extends animal
' for true polymorphism:
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
' for polymorphism emulation:
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As dog) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As dog) As String
Declare Static Sub type_callback_sub (ByRef As dog)
Declare Constructor ()
' for all:
Private:
Dim As String animal_type = "dog"
End Type
' for true polymorphism:
' override_sub methods for dog object:
Virtual Function dog.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function dog.speak_override_fct () As String
Return "Woof!"
End Function
Virtual Sub dog.type_override_sub ()
Print This.animal_type
End Sub
' for polymorphism emulation:
Static As Any Ptr dog.callback_table(0 To 2) = {@dog.addr_callback_fct, @dog.speak_callback_fct, @dog.type_callback_sub}
'callback_sub methods + constructor for dog object:
Static Function dog.addr_callback_fct (ByRef d As dog) As animal Ptr
Return @d
End Function
Static Function dog.speak_callback_fct (ByRef d As dog) As String
Return "Woof!"
End Function
Static Sub dog.type_callback_sub (ByRef d As dog)
Print d.animal_type
End Sub
Constructor dog ()
This.callback_ptr = @callback_table(0)
End Constructor
'Derived-type cat:
Type cat Extends animal
' for true polymorphism:
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
' for polymorphism emulation:
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As cat) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As cat) As String
Declare Static Sub type_callback_sub (ByRef As cat)
Declare Constructor ()
' for all:
Private:
Dim As String animal_type = "cat"
End Type
' for true polymorphism:
' override_sub mehods for cat object:
Virtual Function cat.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function cat.speak_override_fct () As String
Return "Meow!"
End Function
Virtual Sub cat.type_override_sub ()
Print This.animal_type
End Sub
' for polymorphism emulation:
Static As Any Ptr cat.callback_table(0 To 2) = {@cat.addr_callback_fct, @cat.speak_callback_fct, @cat.type_callback_sub}
' callback_sub mehods + constructor for cat object:
Static Function cat.addr_callback_fct (ByRef c As cat) As animal Ptr
Return @c
End Function
Static Function cat.speak_callback_fct (ByRef c As cat) As String
Return "Meow!"
End Function
Static Sub cat.type_callback_sub (ByRef c As cat)
Print c.animal_type
End Sub
Constructor cat ()
This.callback_ptr = @callback_table(0)
End Constructor
'Derived-type bird:
Type bird Extends animal
' for true polymorphism:
Public:
Declare Virtual Function addr_override_fct () As animal Ptr Override
Declare Virtual Function speak_override_fct () As String Override
Declare Virtual Sub type_override_sub () Override
' for polymorphism emulation:
Private:
Static As Any Ptr callback_table(0 To 2)
Public:
Declare Static Function addr_callback_fct (ByRef As bird) As animal Ptr
Declare Static Function speak_callback_fct (ByRef As bird) As String
Declare Static Sub type_callback_sub (ByRef As bird)
Declare Constructor ()
' for all:
Private:
Dim As String animal_type = "bird"
End Type
' for true polymorphism:
' override_sub mehods for bird object:
Virtual Function bird.addr_override_fct () As animal Ptr
Return @This
End Function
Virtual Function bird.speak_override_fct () As String
Return "Cheep!"
End Function
Virtual Sub bird.type_override_sub ()
Print This.animal_type
End Sub
' for polymorphism emulation:
Static As Any Ptr bird.callback_table(0 To 2) = {@bird.addr_callback_fct, @bird.speak_callback_fct, @bird.type_callback_sub}
' callback_sub mehods + constructor for bird object:
Static Function bird.addr_callback_fct (ByRef b As bird) As animal Ptr
Return @b
End Function
Static Function bird.speak_callback_fct (ByRef b As bird) As String
Return "Cheep!"
End Function
Static Sub bird.type_callback_sub (ByRef b As bird)
Print b.animal_type
End Sub
Constructor bird ()
This.callback_ptr = @callback_table(0)
End Constructor
'Create a dog and cat and bird dynamic instances referred through an animal pointer list:
Dim As dog Ptr p_my_dog = New dog
Dim As cat Ptr p_my_cat = New cat
Dim As bird Ptr p_my_bird = New bird
Dim As animal Ptr animal_list (1 To ...) = {p_my_dog, p_my_cat, p_my_bird}
'Have the animals speak and eat:
Print "SUB-TYPE POLYMORPHISM", "@object", "speak", "type"
For I As Integer = LBound(animal_list) To UBound(animal_list)
Print " animal #" & I & ":"
' for override_sub:
Print " true operating:",
Print animal_list(I)->addr_override_fct(), 'real polymorphism
Print animal_list(I)->speak_override_fct(), 'real polymorphism
animal_list(I)->type_override_sub() 'real polymorphism
' for polymorphism emulation:
Print " by emulation:",
Print animal_list(I)->addr_callback_fct(), 'emulated polymorphism
Print animal_list(I)->speak_callback_fct(), 'emulated polymorphism
animal_list(I)->type_callback_sub() 'emulated polymorphism
Next I
Sleep
Delete p_my_dog
Delete p_my_cat
Delete p_my_bird
SUB-TYPE POLYMORPHISM @object speak type animal #1: true operating: 11217472 Woof! dog by emulation: 11217472 Woof! dog animal #2: true operating: 11217552 Meow! cat by emulation: 11217552 Meow! cat animal #3: true operating: 11217632 Cheep! bird by emulation: 11217632 Cheep! bird
3. Demangle typenames from RTTI info
Extraction of the mangled typename from the RTTI info:
Example of mangled typenames extraction from RTTI info, for an inheritance structure (three derived level) declared inside a namespace block:
Implementation of the mangled typenames
- From the instance address, the RTTI info pointer of the type of the instance is accessed through a double indirection (with offsets: [0][-1]).
- The RTTI info pointer chaining described above allows to access RTTI info of the selected type in the inheritance hierarchy (up to the Object built-in type). This is done by means of an iteration on the pointer indirection (with offset: [+2]).
- Then the selected mangled typename is accessed (final indirection with offset: [+1])
Function 'mangledTypeNameFromRTTI()' to extract the mangled typenames:- The RTTI info pointer chaining described above allows to access RTTI info of the selected type in the inheritance hierarchy (up to the Object built-in type). This is done by means of an iteration on the pointer indirection (with offset: [+2]).
- Then the selected mangled typename is accessed (final indirection with offset: [+1])
Function mangledTypeNameFromRTTI (Byval po As Object Ptr, Byval baseIndex As Integer = 0) As String ' Function to get any mangled-typename in the inheritance up hierarchy ' of the type of an instance (address: 'po') compatible with the built-in 'Object' ' ' ('baseIndex = 0' to get the mangled-typename of the instance) ' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing) ' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing) ' (.....) ' Dim As String s Dim As Zstring Ptr pz Dim As Any Ptr p = Cptr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info For I As Integer = baseIndex To -1 p = Cptr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info If p = 0 Then Return s Next I pz = Cptr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename s = *pz Return s End Function
Namespace oop
Type parent Extends Object
End Type
Type child Extends parent
End Type
Type grandchild Extends child
End Type
End Namespace
Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any mangled-typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the mangled-typename of the instance)
' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
s = *pz
Return s
End Function
Dim As Object Ptr p = New oop.grandchild
Print "Mangled typenames list, from RTTI info:"
Print " " & mangledTypeNameFromRTTI(p, 0)
Print " " & mangledTypeNameFromRTTI(p, -1)
Print " " & mangledTypeNameFromRTTI(p, -2)
Print " " & mangledTypeNameFromRTTI(p, -3)
Delete p
Sleep
Output:Type parent Extends Object
End Type
Type child Extends parent
End Type
Type grandchild Extends child
End Type
End Namespace
Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any mangled-typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the mangled-typename of the instance)
' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
s = *pz
Return s
End Function
Dim As Object Ptr p = New oop.grandchild
Print "Mangled typenames list, from RTTI info:"
Print " " & mangledTypeNameFromRTTI(p, 0)
Print " " & mangledTypeNameFromRTTI(p, -1)
Print " " & mangledTypeNameFromRTTI(p, -2)
Print " " & mangledTypeNameFromRTTI(p, -3)
Delete p
Sleep
Mangled typenames list, from RTTI info: N3OOP10GRANDCHILDE N3OOP5CHILDE N3OOP6PARENTE 6OBJECT
From the above output, the mangling process on typenames can be highlighted with the following formatting:
Extract the typenames (demangled) from RTTI info
N3OOP10GRANDCHILDE
(for 'oop.grandchild')
N3OOP5CHILDE
(for 'oop.child')
N3OOP6PARENTE
(for 'oop.parent')
6OBJECT
(for 'Object')
Details on the the mangling process on typenames in the RTTI info:(for 'oop.grandchild')
N3OOP5CHILDE
(for 'oop.child')
N3OOP6PARENTE
(for 'oop.parent')
6OBJECT
(for 'Object')
- The mangled typename is a Zstring (ended by the null character).
- Each component (one dot as separator) of the full typename (converted to uppercase) is preceded by its number of characters encoded in ASCII itself (based on length-prefixed strings).
- When the type is inside at least one namespace, the mangled typename string begins with an additional "N" and ends with an additional "E".
- Each component (one dot as separator) of the full typename (converted to uppercase) is preceded by its number of characters encoded in ASCII itself (based on length-prefixed strings).
- When the type is inside at least one namespace, the mangled typename string begins with an additional "N" and ends with an additional "E".
(prefix "N" and suffix "E" from Nested-name ... Ending)
The previous function ('mangledTypeNameFromRTTI()') can be now completed with a demangling process.
Function 'typeNameFromRTTI()' to extract the demangled typenames:
Previous example completed with the above function:
Extract at once the Typename (demangled) and all those of its base-types hierarchy, from RTTI infoFunction 'typeNameFromRTTI()' to extract the demangled typenames:
Function typeNameFromRTTI (Byval po As Object Ptr, Byval baseIndex As Integer = 0) As String ' Function to get any typename in the inheritance up hierarchy ' of the type of an instance (address: 'po') compatible with the built-in 'Object' ' ' ('baseIndex = 0' to get the typename of the instance) ' ('baseIndex = -1' to get the base.typename of the instance, or "" if not existing) ' ('baseIndex = -2' to get the base.base.typename of the instance, or "" if not existing) ' (.....) ' Dim As String s Dim As Zstring Ptr pz Dim As Any Ptr p = Cptr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info For I As Integer = baseIndex To -1 p = Cptr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info If p = 0 Then Return s Next I pz = Cptr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename Do Do While (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0") If (*pz)[0] = 0 Then Return s pz += 1 Loop Dim As Integer N = Val(*pz) Do pz += 1 Loop Until (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0") If s <> "" Then s &= "." s &= Left(*pz, N) pz += N Loop End Function
Namespace oop
Type parent Extends Object
End Type
Type child Extends parent
End Type
Type grandchild Extends child
End Type
End Namespace
Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any mangled-typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the mangled-typename of the instance)
' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
s = *pz
Return s
End Function
Function typeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the typename of the instance)
' ('baseIndex = -1' to get the base.typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base.typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
Do
Do While (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If (*pz)[0] = 0 Then Return s
pz += 1
Loop
Dim As Integer N = Val(*pz)
Do
pz += 1
Loop Until (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If s <> "" Then s &= "."
s &= Left(*pz, N)
pz += N
Loop
End Function
Dim As Object Ptr p = New oop.grandchild
Print "Mangled typenames list, from RTTI info:"
Print " " & mangledTypeNameFromRTTI(p, 0)
Print " " & mangledTypeNameFromRTTI(p, -1)
Print " " & mangledTypeNameFromRTTI(p, -2)
Print " " & mangledTypeNameFromRTTI(p, -3)
Print
Print "Typenames (demangled) list, from RTTI info:"
Print " " & typeNameFromRTTI(p, 0)
Print " " & typeNameFromRTTI(p, -1)
Print " " & typeNameFromRTTI(p, -2)
Print " " & typeNameFromRTTI(p, -3)
Delete p
Sleep
Output:Type parent Extends Object
End Type
Type child Extends parent
End Type
Type grandchild Extends child
End Type
End Namespace
Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any mangled-typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the mangled-typename of the instance)
' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
s = *pz
Return s
End Function
Function typeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the typename of the instance)
' ('baseIndex = -1' to get the base.typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base.typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
Do
Do While (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If (*pz)[0] = 0 Then Return s
pz += 1
Loop
Dim As Integer N = Val(*pz)
Do
pz += 1
Loop Until (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If s <> "" Then s &= "."
s &= Left(*pz, N)
pz += N
Loop
End Function
Dim As Object Ptr p = New oop.grandchild
Print "Mangled typenames list, from RTTI info:"
Print " " & mangledTypeNameFromRTTI(p, 0)
Print " " & mangledTypeNameFromRTTI(p, -1)
Print " " & mangledTypeNameFromRTTI(p, -2)
Print " " & mangledTypeNameFromRTTI(p, -3)
Print "Typenames (demangled) list, from RTTI info:"
Print " " & typeNameFromRTTI(p, 0)
Print " " & typeNameFromRTTI(p, -1)
Print " " & typeNameFromRTTI(p, -2)
Print " " & typeNameFromRTTI(p, -3)
Delete p
Sleep
Mangled typenames list, from RTTI info: N3OOP10GRANDCHILDE N3OOP5CHILDE N3OOP6PARENTE 6OBJECT Typenames (demangled) list, from RTTI info: OOP.GRANDCHILD OOP.CHILD OOP.PARENT OBJECT
Simply by calling the previous function in a loop with a decreasing parameter 'baseIndex' (from the value 0) and to stop it as soon as an empty string is returned. Finaly by returning a string containing the different typenames with a hierarchic separator between each.
Function 'typeNameHierarchyFromRTTI()' to extract the Typename (demangled) and all those of its base-types hierarchy:
Previous example again completed with the above function:
Compare the typename (demangled) extracted from RTTI info to a string variableFunction 'typeNameHierarchyFromRTTI()' to extract the Typename (demangled) and all those of its base-types hierarchy:
Function typeNameHierarchyFromRTTI (Byval po As Object Ptr) As String ' Function to get the typename inheritance up hierarchy ' of the type of an instance (address: po) compatible with the built-in 'Object' ' Dim As String s = TypeNameFromRTTI(po) Dim As Integer i = -1 Do Dim As String s0 = typeNameFromRTTI(po, i) If s0 = "" Then Exit Do s &= "->" & s0 i -= 1 Loop Return s End Function
Namespace oop
Type parent Extends Object
End Type
Type child Extends parent
End Type
Type grandchild Extends child
End Type
End Namespace
Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any mangled-typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the mangled-typename of the instance)
' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
s = *pz
Return s
End Function
Function typeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the typename of the instance)
' ('baseIndex = -1' to get the base.typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base.typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
Do
Do While (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If (*pz)[0] = 0 Then Return s
pz += 1
Loop
Dim As Integer N = Val(*pz)
Do
pz += 1
Loop Until (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If s <> "" Then s &= "."
s &= Left(*pz, N)
pz += N
Loop
End Function
Function typeNameHierarchyFromRTTI (ByVal po As Object Ptr) As String
' Function to get the typename inheritance up hierarchy
' of the type of an instance (address: po) compatible with the built-in 'Object'
'
Dim As String s = TypeNameFromRTTI(po)
Dim As Integer i = -1
Do
Dim As String s0 = typeNameFromRTTI(po, i)
If s0 = "" Then Exit Do
s &= "->" & s0
i -= 1
Loop
Return s
End Function
Dim As Object Ptr p = New oop.grandchild
Print "Mangled typenames list, from RTTI info:"
Print " " & mangledTypeNameFromRTTI(p, 0)
Print " " & mangledTypeNameFromRTTI(p, -1)
Print " " & mangledTypeNameFromRTTI(p, -2)
Print " " & mangledTypeNameFromRTTI(p, -3)
Print
Print "Typenames (demangled) list, from RTTI info:"
Print " " & typeNameFromRTTI(p, 0)
Print " " & typeNameFromRTTI(p, -1)
Print " " & typeNameFromRTTI(p, -2)
Print " " & typeNameFromRTTI(p, -3)
Print
Print "Typename (demangled) and all those of its base-types hierarchy, from RTTI info:"
Print " " & typeNameHierarchyFromRTTI(p)
Delete p
Sleep
Output:Type parent Extends Object
End Type
Type child Extends parent
End Type
Type grandchild Extends child
End Type
End Namespace
Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any mangled-typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the mangled-typename of the instance)
' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
s = *pz
Return s
End Function
Function typeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the typename of the instance)
' ('baseIndex = -1' to get the base.typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base.typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
Do
Do While (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If (*pz)[0] = 0 Then Return s
pz += 1
Loop
Dim As Integer N = Val(*pz)
Do
pz += 1
Loop Until (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If s <> "" Then s &= "."
s &= Left(*pz, N)
pz += N
Loop
End Function
Function typeNameHierarchyFromRTTI (ByVal po As Object Ptr) As String
' Function to get the typename inheritance up hierarchy
' of the type of an instance (address: po) compatible with the built-in 'Object'
'
Dim As String s = TypeNameFromRTTI(po)
Dim As Integer i = -1
Do
Dim As String s0 = typeNameFromRTTI(po, i)
If s0 = "" Then Exit Do
s &= "->" & s0
i -= 1
Loop
Return s
End Function
Dim As Object Ptr p = New oop.grandchild
Print "Mangled typenames list, from RTTI info:"
Print " " & mangledTypeNameFromRTTI(p, 0)
Print " " & mangledTypeNameFromRTTI(p, -1)
Print " " & mangledTypeNameFromRTTI(p, -2)
Print " " & mangledTypeNameFromRTTI(p, -3)
Print "Typenames (demangled) list, from RTTI info:"
Print " " & typeNameFromRTTI(p, 0)
Print " " & typeNameFromRTTI(p, -1)
Print " " & typeNameFromRTTI(p, -2)
Print " " & typeNameFromRTTI(p, -3)
Print "Typename (demangled) and all those of its base-types hierarchy, from RTTI info:"
Print " " & typeNameHierarchyFromRTTI(p)
Delete p
Sleep
Mangled typenames list, from RTTI info: N3OOP10GRANDCHILDE N3OOP5CHILDE N3OOP6PARENTE 6OBJECT Typenames (demangled) list, from RTTI info: OOP.GRANDCHILD OOP.CHILD OOP.PARENT OBJECT Typename (demangled) and all those of its base-types hierarchy, from RTTI info: OOP.GRANDCHILD->OOP.CHILD->OOP.PARENT->OBJECT
As the various steps of demangling, the successive elements of the typname extracted from the RTTI info are compared with those of the chain provided (as soon as an element is different, "false" is returned immediately).
Function 'typeNameEqualFromRTTI()' to compared the typename (demangled) extracted from RTTI info to a string variable:
Previous example finally completed with the above function:
Function 'typeNameEqualFromRTTI()' to compared the typename (demangled) extracted from RTTI info to a string variable:
Function typeNameEqualFromRTTI (Byval po As Object Ptr, Byref typeName As String) As Boolean ' Function to get true if the instance typename (address: po) is the same than the passed string ' Dim As String t = Ucase(typeName) Dim As ZString Ptr pz = Cptr(Any Ptr Ptr Ptr Ptr, po)[0][-1][1] ' Ptr to Mangled Typename Dim As Integer i = 1 Do Do While (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0") If (*pz)[0] = 0 Then Return True pz += 1 Loop Dim As Integer N = Val(*pz) Do pz += 1 Loop Until (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0") If i > 1 Then If Mid(t, i, 1) <> "." Then Return False Else i += 1 End If If Mid(t, i, N) <> Left(*pz, N) Then Return False Else pz += N : i += N Loop End Function
Namespace oop
Type parent Extends Object
End Type
Type child Extends parent
End Type
Type grandchild Extends child
End Type
End Namespace
Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any mangled-typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the mangled-typename of the instance)
' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
s = *pz
Return s
End Function
Function typeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the typename of the instance)
' ('baseIndex = -1' to get the base.typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base.typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
Do
Do While (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If (*pz)[0] = 0 Then Return s
pz += 1
Loop
Dim As Integer N = Val(*pz)
Do
pz += 1
Loop Until (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If s <> "" Then s &= "."
s &= Left(*pz, N)
pz += N
Loop
End Function
Function typeNameHierarchyFromRTTI (ByVal po As Object Ptr) As String
' Function to get the typename inheritance up hierarchy
' of the type of an instance (address: po) compatible with the built-in 'Object'
'
Dim As String s = TypeNameFromRTTI(po)
Dim As Integer i = -1
Do
Dim As String s0 = typeNameFromRTTI(po, i)
If s0 = "" Then Exit Do
s &= "->" & s0
i -= 1
Loop
Return s
End Function
Function typeNameEqualFromRTTI (ByVal po As Object Ptr, ByRef typeName As String) As Boolean
' Function to get true if the instance typename (address: po) is the same than the passed string
'
Dim As String t = UCase(typeName)
Dim As ZString Ptr pz = CPtr(Any Ptr Ptr Ptr Ptr, po)[0][-1][1] ' Ptr to Mangled Typename
Dim As Integer i = 1
Do
Do While (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If (*pz)[0] = 0 Then Return True
pz += 1
Loop
Dim As Integer N = Val(*pz)
Do
pz += 1
Loop Until (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If i > 1 Then
If Mid(t, i, 1) <> "." Then Return False Else i += 1
End If
If Mid(t, i, N) <> Left(*pz, N) Then Return False Else pz += N : i += N
Loop
End Function
Dim As Object Ptr p = New oop.grandchild
Print "Mangled typenames list, from RTTI info:"
Print " " & mangledTypeNameFromRTTI(p, 0)
Print " " & mangledTypeNameFromRTTI(p, -1)
Print " " & mangledTypeNameFromRTTI(p, -2)
Print " " & mangledTypeNameFromRTTI(p, -3)
Print
Print "Typenames (demangled) list, from RTTI info:"
Print " " & typeNameFromRTTI(p, 0)
Print " " & typeNameFromRTTI(p, -1)
Print " " & typeNameFromRTTI(p, -2)
Print " " & typeNameFromRTTI(p, -3)
Print
Print "Typename (demangled) and all those of its base-types hierarchy, from RTTI info:"
Print " " & typeNameHierarchyFromRTTI(p)
Delete p
Print
p = New oop.child
Print "Is the typename of an oop.child instance the same as ""child""?"
Print " " & typeNameEqualFromRTTI(p, "child")
Print "Is the typename of an oop.child instance the same as ""oop.child""?"
Print " " & typeNameEqualFromRTTI(p, "oop.child")
Print "Is the typename of an oop.child instance the same as ""oop.grandchild""?"
Print " " & typeNameEqualFromRTTI(p, "oop.grandchild")
Print "Is the typename of an oop.child instance the same as ""oop.parent""?"
Print " " & typeNameEqualFromRTTI(p, "oop.parent")
Delete p
Sleep
Output:Type parent Extends Object
End Type
Type child Extends parent
End Type
Type grandchild Extends child
End Type
End Namespace
Function mangledTypeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any mangled-typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the mangled-typename of the instance)
' ('baseIndex = -1' to get the base mangled-typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base mangled-typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
s = *pz
Return s
End Function
Function typeNameFromRTTI (ByVal po As Object Ptr, ByVal baseIndex As Integer = 0) As String
' Function to get any typename in the inheritance up hierarchy
' of the type of an instance (address: 'po') compatible with the built-in 'Object'
'
' ('baseIndex = 0' to get the typename of the instance)
' ('baseIndex = -1' to get the base.typename of the instance, or "" if not existing)
' ('baseIndex = -2' to get the base.base.typename of the instance, or "" if not existing)
' (.....)
'
Dim As String s
Dim As ZString Ptr pz
Dim As Any Ptr p = CPtr(Any Ptr Ptr Ptr, po)[0][-1] ' Ptr to RTTI info
For I As Integer = baseIndex To -1
p = CPtr(Any Ptr Ptr, p)[2] ' Ptr to Base RTTI info of previous RTTI info
If p = 0 Then Return s
Next I
pz = CPtr(Any Ptr Ptr, p)[1] ' Ptr to mangled-typename
Do
Do While (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If (*pz)[0] = 0 Then Return s
pz += 1
Loop
Dim As Integer N = Val(*pz)
Do
pz += 1
Loop Until (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If s <> "" Then s &= "."
s &= Left(*pz, N)
pz += N
Loop
End Function
Function typeNameHierarchyFromRTTI (ByVal po As Object Ptr) As String
' Function to get the typename inheritance up hierarchy
' of the type of an instance (address: po) compatible with the built-in 'Object'
'
Dim As String s = TypeNameFromRTTI(po)
Dim As Integer i = -1
Do
Dim As String s0 = typeNameFromRTTI(po, i)
If s0 = "" Then Exit Do
s &= "->" & s0
i -= 1
Loop
Return s
End Function
Function typeNameEqualFromRTTI (ByVal po As Object Ptr, ByRef typeName As String) As Boolean
' Function to get true if the instance typename (address: po) is the same than the passed string
'
Dim As String t = UCase(typeName)
Dim As ZString Ptr pz = CPtr(Any Ptr Ptr Ptr Ptr, po)[0][-1][1] ' Ptr to Mangled Typename
Dim As Integer i = 1
Do
Do While (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If (*pz)[0] = 0 Then Return True
pz += 1
Loop
Dim As Integer N = Val(*pz)
Do
pz += 1
Loop Until (*pz)[0] > Asc("9") Orelse (*pz)[0] < Asc("0")
If i > 1 Then
If Mid(t, i, 1) <> "." Then Return False Else i += 1
End If
If Mid(t, i, N) <> Left(*pz, N) Then Return False Else pz += N : i += N
Loop
End Function
Dim As Object Ptr p = New oop.grandchild
Print "Mangled typenames list, from RTTI info:"
Print " " & mangledTypeNameFromRTTI(p, 0)
Print " " & mangledTypeNameFromRTTI(p, -1)
Print " " & mangledTypeNameFromRTTI(p, -2)
Print " " & mangledTypeNameFromRTTI(p, -3)
Print "Typenames (demangled) list, from RTTI info:"
Print " " & typeNameFromRTTI(p, 0)
Print " " & typeNameFromRTTI(p, -1)
Print " " & typeNameFromRTTI(p, -2)
Print " " & typeNameFromRTTI(p, -3)
Print "Typename (demangled) and all those of its base-types hierarchy, from RTTI info:"
Print " " & typeNameHierarchyFromRTTI(p)
Delete p
p = New oop.child
Print "Is the typename of an oop.child instance the same as ""child""?"
Print " " & typeNameEqualFromRTTI(p, "child")
Print "Is the typename of an oop.child instance the same as ""oop.child""?"
Print " " & typeNameEqualFromRTTI(p, "oop.child")
Print "Is the typename of an oop.child instance the same as ""oop.grandchild""?"
Print " " & typeNameEqualFromRTTI(p, "oop.grandchild")
Print "Is the typename of an oop.child instance the same as ""oop.parent""?"
Print " " & typeNameEqualFromRTTI(p, "oop.parent")
Delete p
Sleep
Mangled typenames list, from RTTI info: N3OOP10GRANDCHILDE N3OOP5CHILDE N3OOP6PARENTE 6OBJECT Typenames (demangled) list, from RTTI info: OOP.GRANDCHILD OOP.CHILD OOP.PARENT OBJECT Typename (demangled) and all those of its base-types hierarchy, from RTTI info: OOP.GRANDCHILD->OOP.CHILD->OOP.PARENT->OBJECT Is the typename of an oop.child instance the same as "child"? false Is the typename of an oop.child instance the same as "oop.child"? true Is the typename of an oop.child instance the same as "oop.grandchild"? false Is the typename of an oop.child instance the same as "oop.parent"? false
See also:
Back to Programmer's Guide