<html> <head> <title>How to write a class object for a C++ class</title> <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1"> <link rel="stylesheet" href="highlight.css" type="text/css"> </head> <body bgcolor="#FFFFFF" text="#000000"> <p><font size="6"><i><b>How to write a class object for a C++ class</b></i></font></p> <p><font size="4">This topic is fundamental in the understanding of how the class object and the object hierarchy framework interact with each other. Let's say we have a simple class:</font></p> <pre> <span class="key">class </span>Simple { <span class="key">public</span>: Simple(); <span class="key">virtual </span>~Simple(); <span class="typ">void </span>DoSomething(); <span class="typ">void </span>PrintString(<span class="typ">const </span>std::string& s); <span class="typ">void </span>PrintInt(<span class="typ">int </span>i); <span class="typ">void </span>PrintFloat(<span class="typ">float </span>f); <span class="typ">void </span>PrintBool(<span class="typ">bool </span>b); }; </pre> <p><font size="4">Now, in order to write a class object for this class we must do two things. First, the class must derive from the zeitgeist::Object class (or one of its descendants, especially Leaf and Node if instances of this class are to live in the object hierarchy). In addition to this, a class object must be declared and defined, which serves as a factory for instances of this class.</font></p> <p><font size="4">The first step is performed easily:</font></p> <pre><span class="dir">#include <zeitgeist/leaf.h> </span> <span class="key">class </span>Simple : <span class="key">public </span>zeitgeist::Leaf { <span class="key">public</span>: Simple(); <span class="key">virtual </span>~Simple(); <span class="typ">void </span>DoSomething(); <span class="typ">void </span>PrintString(<span class="typ">const </span>std::string& s); <span class="typ">void </span>PrintInt(<span class="typ">int </span>i); <span class="typ">void </span>PrintFloat(<span class="typ">float </span>f); <span class="typ">void </span>PrintBool(<span class="typ">bool </span>b); }; </pre> <p><font size="4">Now, we just have to write a class object for this class. As this is a pretty repetitive procedure, several helper-macros exist to make this as painless as possible. First, we declare the class object. This is done in the header file with the DECLARE_CLASS()-macro:</font></p> <pre><span class="dir">#include <zeitgeist/leaf.h> </span> <span class="key">class </span>Simple : <span class="key">public </span>zeitgeist::Leaf { <span class="key">public</span>: Simple(); <span class="key">virtual </span>~Simple(); <span class="typ">void </span>DoSomething(); <span class="typ">void </span>PrintString(<span class="typ">const </span>std::string& s); <span class="typ">void </span>PrintInt(<span class="typ">int </span>i); <span class="typ">void </span>PrintFloat(<span class="typ">float </span>f); <span class="typ">void </span>PrintBool(<span class="typ">bool </span>b); }; DECLARE_CLASS(Simple); </pre> <p><font size="4">With this macro, we declare the class object. If Simple would have been an abstract base class (containing one or more pure virtual functions) we would have needed to use the DECLARE_ABSTRACTCLASS()-macro instead. What do these macros actually do. Both create a new class with the mangled name Class_XXXX, where XXXX is the name of the class. In our case this would be Class_Simple. This class is derived from zeitgeist::Class. In the case of DECLARE_CLASS() the macro also provides a CreateInstance() function, which creates an instance of the Simple class (upcast to zeitgeist::Object). DECLARE_ABSTRACTCLASS() does not do this, as it is impossible to create an instance of an abstract class. It inherits the base behavior from zeitgeist::Class, which just returns NULL. In addition to this, both macros declare a DefineClass() member function, which needs to be implemented to define the class object fully. This is done in an additional CPP file. If the class above was implemented in the files simple.h and simple.cpp, the accompanying class object should be placed in the file simple_c.cpp. This naming convention has been found useful during development and should be adopted. A minimal simple_c.cpp should look like this:</font></p> <pre><span class="dir">#include </span><span class="dstr">"simple.h"</span><span class="dir"></span> <span class="key">using namespace </span>zeitgeist; <span class="typ">void </span>CLASS(Simple)::DefineClass() { DEFINE_BASECLASS(zeitgeist/Leaf); } </pre> <p><font size="4">The CLASS()-macro is used to identify the name of the class object. In the above example, it just resolves to Class_Simple. DEFINE_BASECLASS() is used to identify the base class of the class described by this class object. This can appear multiple times to allow for multiple inheritance. We now have a working class object. The problem is, that the object hierarchy does not know this class object, yet. So, we can't really use it. The <a href="class_register.html">next HowTo</a> explains how to register these class objects.</font></p> </body> </html>