CObject
CClass Struct Reference

First variables in every object's memory allocation. More...

#include <Class.h>

Data Fields

void * _rt
 
size_t _vo
 

Detailed Description

This appears as the first member in all class and interface structures. The CObject and CInterface structure has this as their first member. By including CObject or CInterface as the first member in another structure, this becomes that structures first member.
By doing this, a pointer to any object, which has as it's first member one of struct CObject or struct CInterface, can be safely type cast to a pointer to a struct CClass.
This is used to back track to the base address of an object and the base address of the virtual table. It is very important that this structure is the first member in every class/interface structure.
This works because of the C99 standard in ISO/IEC 9899 6.7.2.1.13, which says in part:
"A pointer to a structure object, suitably converted, points to its initial member (or if that member is a bit-field, then to the unit in which it resides), and vice versa. There may be unnamed padding within a structure object, but not at its beginning."
Consider a class hierchy:

|-------------------------|       |-------------------------|        |---------|
| ClassB                  | ----> | ClassA                  | -----> | CObject |
|-------------------------|       |-------------------------|   |    |---------|
| int varB                |       | int varA                |   |
|-------------------------|       |-------------------------|   |--> |-----------------------------|
| void methodB( ClassB* ) |       | void methodA( ClassA* ) |   |    | Interface0                  |
|-------------------------|       |-------------------------|   |    |-----------------------------|
                                                                |    | void method0( Interface0* ) |
                                                                |    |-----------------------------|
                                                                |
                                                                |--> |-----------------------------|
                                                                     | Interface1                  |
                                                                     |-----------------------------|
                                                                     | void method1( Interface1* ) |
                                                                     |-----------------------------|

where ClassA inherits from CObject and implements Interface0 and Interface1. ClassB inherits from ClassA. If there is a variable of type ClassB:

ClassB* anObject;

Then in memory the layout looks like this:

                      --------------------------------------------
                      |                                    |  |  |
                      |                                    |  |  |
            anObject: --->  | void* C_ROOT               | -  |  |
                            | size_t C_VTABLE_OFFSET = 0 |    |  |
         -------------------| const void* C_VTABLE       |    |  |                         
         |                  | void (*free)( void* )      |    |  |
         |     Interface0:  | void* C_ROOT               | ---   |
         |                  | size_t C_VTABLE_OFFSET = 2 |       |
         |     Interface1:  | void* C_ROOT               | -------
         |                  | size_t C_VTABLE_OFFSET = 3 |
         |         ClassA:  | int varA                   |
         |         ClassB:  | int varB                   |
         |
         |
         ----> vtable --> | void (*CDestructor)( void* )    |
                          | void (*methodA)( ClassA* )      |
                          | void (*method0)( Interface0* )  |
                          | void (*_method1)( Interface1* ) |
                          | void (*methodB)( ClassB* )      |

Given this mapping of pointers, the virtual table can always be found and the entire objects memory location known regardless of the pointer reference. For example, with a reference to Interface0 (5'th row in layout above), the virtual table is found by using C_ROOT to find the top of the object's memory, then going to the third row to get a pointer to the virtual table. Then, the offset into the virtual table of Interface0's methods is found by using the C_VTABLE_OFFSET from the Interface0 reference. Note, the layout of the virtual table is different when function overriding is used. In this example, ClassA doesn't override any methods from CObject and ClassB doesn't override any methods from ClassA and/or CObject.

The virtual tables leverage the 6.7.2.1.13 rule as well. Each class' table is declared such that the super class' virtual table is always the first member of the structure. By doing this, a class' virtual table can always be safetly type cast to a table of the super class. The same is not true interfaces, hence, their table offset value is never zero.


The documentation for this struct was generated from the following file: