RTTI

From WxWiki
Jump to: navigation, search

This page details ways to get the most out of wxWidget's powerful RTTI capability. wxWidgets maintains a global array of wxClassInfo objects which contains information about each class. In order to have your class put in that array, you need to insert macros in your source code.

Put a Class in wxWidget's RTTI

Add a Class Declaration

Put DECLARE_DYNAMIC_CLASS in your class's declaration. (DECLARE_CLASS is supported but should be avoided; it is less specific.) There is also a DECLARE_ABSTRACT_CLASS macro which is the same as the other two variants but may make your intentions more clear.

  // example
  class wxMyClass : public wxObject // Must derive from wxObject
  {
     //...
     DECLARE_DYNAMIC_CLASS(wxMyClass);
  };

Note that having multiple base classes is okay as long as wxObject is the first one.

To understand what the DECLARE_DYNAMIC_CLASS variants do, take a look at the definition of the macro:

#define DECLARE_DYNAMIC_CLASS(name)           \
 public:                                      \
  static wxClassInfo ms_classInfo;            \
  static wxObject* wxCreateObject();          \
  virtual wxClassInfo *GetClassInfo() const   \
   { return &name::ms_classInfo; }

Two member functions, wxCreateObject and GetClassInfo are put in there. Note that you don't really need these at all, and if you want to play with fire you could just put ms_classInfo in there (the name of the class info member doesn't matter either).

Invoke the Macro

Place one of the following macros in your source file:

  • IMPLEMENT_CLASS(className, baseClassName)
  • IMPLEMENT_CLASS2(className, baseClassName1, baseClassName2) should be used if your class has two parents (Only one or two parents are currently supported, but it is easy to define macros for more base classes. Look at wx/object.h for the definitions of the existing macros and modify as needed.)
  • For classes which can't be instantiated, IMPLEMENT_ABSTRACT_CLASS (or IMPLEMENT_ABSTRACT_CLASS2) must be used instead.
// in a .cpp or .mm file
IMPLEMENT_CLASS(wxMyClass, wxObject);

Here's what happens:

#define IMPLEMENT_DYNAMIC_CLASS(name, basename)                 \
 wxObject* name::wxCreateObject()                               \
  { return new name; }                                          \
 wxClassInfo name::ms_classInfo(wxT(#name),                     \
            &basename::ms_classInfo, NULL,                      \
            (int) sizeof(name),                                 \
            (wxObjectConstructorFn) name::wxCreateObject);

Notice that the constructor of wxClassInfo for the class is called, which in turn calls wxClassInfo::Register. Here's where the "magic" happens:

void wxClassInfo::Register()
{
    // part 1
    if ( !sm_classTable )
    {
        sm_classTable = new wxHashTable(wxKEY_STRING);
    }

    // part 2
    wxASSERT_MSG( sm_classTable->Get(m_className) == NULL,
       _T("class already in RTTI table - have you used IMPLEMENT_DYNAMIC_CLASS() twice (may be by linking some object module(s) twice)?") );
    
    // part 3
    sm_classTable->Put(m_className, (wxObject *)this);
}

Part 1 checks to see if there are any classes in the global array (actually an antiquated wxHashTable--you'll see wxWidgets using a lot of deprecated stuff internally) exists, and if it doesn't, it creates the global array.

Part 2 checks to see if the classinfo has already been registered.

Part 3 puts this classinfo in the global array.

Basic Usage

Getting the wxClassInfo of a Class

In order to get something useful out of those macros, you need to get the class info of a class.

There are three ways to do this:

  • Use CLASSINFO(name) where name is the actual name of the class, not an instance (wxFrame, not MyFrame).
  • Class object->GetClassInfo()
  • Call wxClassInfo::FindClass("name") where name is the name of a class, not an instance.

Advanced Usage

wxWidgets uses these things internally, as do some projects that use wxWidgets.

Finding and Creating Derivatives of a Class

wxWidgets has to use methods like these for wxModule. However, due to wxWidget's compatibility layers, there are at least three different ways to do this - but the way that is compatible with both wxWidgets 2.4.x and 2.5.x is:

wxNode* node;
wxClassInfo::sm_classTable->BeginFind();
node = wxClassInfo::sm_classTable->Next();

while (node)
{
    wxClassInfo* classInfo = (wxClassInfo *)node->GetData();

    if ( classInfo->IsKindOf(CLASSINFO(name)) &&
                          (classInfo != CLASSINFO(name) ))
    {
        //do stuff with classinfo, like create objects
        name* MyInstance = (name*)classInfo->CreateObject();
    }
    node = wxClassInfo::sm_classTable->Next();
}

In the code above, name is the name (not the instance) of the class for which you want to find the derivatives.

Force Link Hacks

Use Force Link Hacks When:

  • You have a source file that is compiled with a class that is in the RTTI array (or you are using indirectly) and
  • Nothing in that source file is being used directly (i.e. you are searching for this class using the method described in the previous section)

Usage

// in source file that contains stuff you don't directly use
#include <wx/html/forcelnk.h>
FORCE_LINK_ME(sourcename);

// in source file that contains stuff you DO directly use
FORCE_LINK(sourcename);

XTI

XTI (eXtended Type Information) - Being developed by Stefan Csomer, was originally made for Borland to ease some compiler operations.

It is undocumented and even a lot of core developers don't know too much about it.

It is supposed to be more powerful than wxWidget's RTTI--take a look at xti.h if you're feeling adventurous.

Resources