|
|
Generics
Reference Manual |
|
Metaclass
Definition
Metaclasses are classes descriptions that allow for dynamic analyse of
instances types at runtime.
CMetaClass type
There are 3 defined types of metaclasses
:
typedef enum
{
METACLASS_GENERIC=0,
METACLASS_DYNAMIC,
METACLASS_CAPSULE
}
TMetaClass; |
generic |
the metaclass describes an
abstract class i.e. a class that declares pure virtual functions |
dynamic |
the metaclass describes a
non abstract class and is able to instanciate it by calling its default
constructor |
capsule |
the metaclass describes a
non abstract class but is not able to
instanciate it because either the described class does not define a
default constructor either the programmer's choice was not to give the
access to this functionality |
A metaclass handles the followings :
- the base definition the described class is derived from
(NULL for the absolute one),
- the metaclass type (dynamic, generic or capsule),
- the described class name (its type as a
CString value),
- the described class tag identification (should not equal
0L),
- the default described class size (sizeof class),
- "a default constructor pointer" of the described class
(only if it is a dynamic one).
A metaclass handles static attributes too. Their definitions
are as follow :
- all declared metaclasses list access for the binary and its
potential modules,
- a function that searches for a metaclass from a given class
name,
- a function that searches for a metaclass from a given class
tag identification,
- a function that checks a derivation status between two
metaclasses,
- a function that searches for derived metaclass described
classes definition,
- a function that returns the declared metaclasses list
hierarchy as a
tree.
typedef NServices::TBuffer <const CMetaClass
*> CMetaClasses;
typedef NServices::TNode
<CMetaClass
> CMetaClassNode;
class CMetaClass
{
// metaclass attributes
public :
const
CMetaClass *
BaseMetaClass;
const
TMetaClass
MetaClassType;
const
UInt32
ClassTag;
const
CString
ClassName;
const
UInt16
ClassSize;
CClass
*
(*ClassInstanciate)
();
// static attributes
public :
static
CMetaClasses
MetaClasses;
static
const CMetaClass *
GetMetaClass
(const CString
&);
static
const CMetaClass *
GetMetaClass
(const UInt32);
static
bool
MetaClassIs
(const
CMetaClass *inBase, const CMetaClass *inCandidate);
static
bool
IsFinal
(const CMetaClass *);
static
CMetaClassNode
GetMetaClassTree
();
// instanciation section
public :
CMetaClass (const CMetaClass * =NULL, const TMetaClass
=METACLASS_GENERIC, const UInt32 =0L,
const CString &
=CString(), const UInt16 =0, CClass * (*) () =NULL);
virtual
~CMetaClass
();
}; |
The CMetaClass constructor and destructor handle the
insertion and deletion of the metaclasses instances into the static
list of the binary defined metaclasses.
There is no initialization
process requirement in order to use the metaclasses facility.
All of them are declared as static constants and are also allocated
before the binary execution entry point is called as described in the
following
"macros
services" section.
CClass base class metaclass
association
The CClass definition is the absolute
abstract metaclassed class definition. Every metaclassed class defines
at least the following functions :
Bool ClassIs (const
CMetaClass *) const; |
A function that dynamically tests the instance definition from a given
metaclass.
virtual const CMetaClass *
GetMetaClass () const; |
A virtual function that returns the correct instance associated
metaclass.
static CClass *
Instanciate (); |
A static function that returns a default instance of the
metaclassed class only if it is a dynamic one. The dynamic
metaclassed class should have a default constructor and the associated
metaclass should be a dynamic one to be able to access it. You should
not use directly this function. It is only defined for the CMetaClass
"CClass * CMetaClass::ClassInstanciate ()" attribute.
Those two last functionnalities are given the
cmetaclass.h
defined macros SECTION_GENERIC_METACLASS, SECTION_CAPSULE_METACLASS and
SECTION_DYNAMIC_METACLASS as described in the following
"macros services"
section.
class CClass
{
// instanciation section
public :
CClass
();
virtual
~CClass ()
=0;
// dynamic definition test
public :
//
instance definition dynamic test
Bool
ClassIs
(const CMetaClass *) const;
//
generic metaclass association
SECTION_GENERIC_METACLASS;
};
// class tag and metaclass declaration
DECLARE_GENERIC_METACLASS ('clss', CClass, NULL); |
The classes metaclasses tags
of the libgenerics are declared using constant characters then
converted to unsigned long. This notation may generate some warnings
when building your code. To avoid those recursive "dummy" unneeded messages, you
can use the
GNU gcc -Wno-multichar option.
Macros services
Some macro are defined to associate the metaclasses to their
classes in order to facilitate the process and to respect the
declaration syntaxes. They are logically separated in 4 sections.
The first macro familly is dedicated to
class associated metaclass code sections i.e. part class prototypes
declarations. There are 3 possible sections types, according to the
metaclasses types that should be associated to the defined class (see "
CMetaClass types"
section above) :
SECTION_GENERIC_METACLASS;
SECTION_CAPSULE_METACLASS;
SECTION_DYNAMIC_METACLASS; |
The second macro familly is about static
constants metaclasses objects and class tag / signature declarations.
Those macros should be used in concordance with the metaclass class
section declared above.
DECLARE_GENERIC_METACLASS
(classtag, class, baseclass);
DECLARE_CAPSULE_METACLASS (classtag, class, baseclass);
DECLARE_DYNAMIC_METACLASS (classtag, class, baseclass); |
The third macro familly should be used
to resolve code of the metaclasses part class prototypes declarations.
There are still 3 available macros.
RESOLVE_GENERIC_METACLASS
(class);
RESOLVE_CAPSULE_METACLASS (class);
RESOLVE_DYNAMIC_METACLASS (class); |
The last macro familly is defined to
facilitate and organize the metaclasses access :
returns
the class tag / signature of a given class type.
returns
the metaclass address of a given class type (const CMetaClass *).
metaclass_cast (instance) |
returns the metaclass address of
a given class instance (virtual const CMetaClass * instance ->
GetMetaClass ()).
returns the instance associated class tag / signature.
METACLASSESLENGTH
METACLASSES(index) |
returns the declared metaclasses
list length and the metaclass of specified index in the global list
respectively.
Deriving a metaclassed
class and testing a class type at runtime
a) As example, consider you want to define your CMyClass class that would be metaclassed described :
"myclass.h"
#include "cclass.h"
class CMyClass : public CClass
{
public :
CMyClass ();
SECTION_xxx_METACLASS;
};
DECLARE_xxx_METACLASS ('mycs', CMyClass, CClass);
"myclass.c"
#include "myclass.h"
RESOLVE_xxx_METACLASS (CMyClass);
CMyClass::CMyClass () : CClass () { }
"main.c"
#include "myclass.h"
...
CClass *MyClass = new CMyClass ();
printf ("%s\n", metaclass_cast(MyClass) ->
ClassName.Get());
// "CMyClass"
printf ("%s\n", __metaclass(CMyClass) ->
ClassName.Get());
// "CMyClass"
printf ("%d\n",
classtag_cast(MyClass));
// "unsigned long('mycs')'"
printf ("%d\n",
__classtag(CMyClass));
// "unsigned long('mycs')"
for (size_t i=0; i<METACLASSESLENGTH; i++)
printf ("%s\n", METACLASSES(i)
-> ClassName.Get());
// "CClass \n
CMyClass"
b) Or, let's
consider you have 3 classes definitions with the following
implementation and a function that should interpret your classes types
to do some particular job (all those samples classes should be
described with metaclasses) :
CClass
|--CA
|--CB
|--CC
void MyFunc (CClass &inClass)
{
// analyse class type
if (inClass.ClassIs (__metaclass(CA)))
printf ("got a CA instance\n");
else if (inClass.ClassIs (__metaclass(CB)))
printf ("got a CB or CC instance\n");
}