Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/objecthierarchy/src/orxonox/core/Identifier.h @ 365

Last change on this file since 365 was 365, checked in by landauf, 16 years ago

added comments

File size: 15.3 KB
Line 
1/*!
2    @file Identifier.h
3    @brief Definition of the Identifier, ClassIdentifier and SubclassIdentifier classes.
4
5    The Identifier contains all needed informations about the class it belongs to:
6     - the name
7     - a list with all objects
8     - parents and childs
9     - the factory, if available
10     - the networkID that can be synchronised with the server
11
12    Every object has a pointer to the Identifier of its class. This allows the use isA(...),
13    isDirectlyA(...), isChildOf(...) and isParentOf(...).
14
15    To create the class-hierarchy, the Identifier has some intern functions and variables.
16
17    Every Identifier is in fact a ClassIdentifier, but they are derived from Identifier.
18
19    SubclassIdentifier is a separated class, acting like an Identifier, but has a given class.
20    You can only assign Identifiers of the given class or a derivative to a SubclassIdentifier.
21*/
22
23#ifndef _Identifier_H__
24#define _Identifier_H__
25
26#include <iostream>
27
28#include "IdentifierList.h"
29#include "ObjectList.h"
30#include "Factory.h"
31
32#define HIERARCHY_VERBOSE false
33
34
35namespace orxonox
36{
37    class BaseObject; // Forward declaration
38
39    // ###############################
40    // ###       Identifier        ###
41    // ###############################
42    //! The Identifier is used to identify the class of an object and to store informations about the class.
43    /**
44        The Identifier contains all needed informations about the class it belongs to:
45         - the name
46         - a list with all objects
47         - parents and childs
48         - the factory, if available
49         - the networkID that can be synchronised with the server
50
51        Every object has a pointer to the Identifier of its class. This allows the use isA(...),
52        isDirectlyA(...), isChildOf(...) and isParentOf(...).
53
54        You can't directly create an Identifier, it's just the base-class for ClassIdentifier.
55    */
56    class Identifier
57    {
58        template <class T>
59        friend class ClassIdentifier; // Forward declaration
60
61        template <class T>
62        friend class SubclassIdentifier; // Forward declaration
63
64        template <class T>
65        friend class ClassFactory; // Forward declaration
66
67        public:
68            /** @brief Sets the Factory. @param facotry The factory to assign */
69            inline void addFactory(BaseFactory* factory) { this->factory_ = factory; }
70
71            BaseObject* fabricate();
72
73            bool isA(const Identifier* identifier) const;
74            bool isDirectlyA(const Identifier* identifier) const;
75            bool isChildOf(const Identifier* identifier) const;
76            bool isParentOf(const Identifier* identifier) const;
77
78            /** @returns the name of the class the Identifier belongs to. */
79            inline const std::string& getName() const { return this->name_; }
80
81            /** @returns the parents of the class the Identifier belongs to. */
82            inline const IdentifierList& getParents() const { return this->parents_; }
83
84            /** @returns the children of the class the Identifier belongs to. */
85            inline IdentifierList& getChildren() const { return *this->children_; }
86
87            /** @returns true, if a branch of the class-hierarchy is getting created, causing all new objects to store their parents. */
88            inline static bool isCreatingHierarchy() { return (hierarchyCreatingCounter_s > 0); }
89
90            /** @returns the NetworkID to identify a class through the network. */
91            inline const unsigned int getNetworkID() const { return this->classID_; }
92
93            void setNetworkID(unsigned int id);
94
95        private:
96            Identifier();
97            Identifier(const Identifier& identifier) {} // don't copy
98            virtual ~Identifier();
99            void initialize(const IdentifierList* parents);
100
101            /**
102                @brief Increases the hierarchyCreatingCounter_s variable, causing all new objects to store their parents.
103            */
104            inline static void startCreatingHierarchy()
105            {
106                hierarchyCreatingCounter_s++;
107#if HIERARCHY_VERBOSE
108                std::cout << "*** Increased Hierarchy-Creating-Counter to " << hierarchyCreatingCounter_s << "\n";
109#endif
110            }
111
112            /**
113                @brief Decreases the hierarchyCreatingCounter_s variable, causing the objects to stop storing their parents.
114            */
115            inline static void stopCreatingHierarchy()
116            {
117                hierarchyCreatingCounter_s--;
118#if HIERARCHY_VERBOSE
119                std::cout << "*** Decreased Hierarchy-Creating-Counter to " << hierarchyCreatingCounter_s << "\n";
120#endif
121            }
122
123            IdentifierList parents_;                    //!< The Parents of the class the Identifier belongs to
124            IdentifierList* children_;                  //!< The Children of the class the Identifier belongs to
125
126            std::string name_;                          //!< The name of the class the Identifier belongs to
127
128            BaseFactory* factory_;                      //!< The Factory, able to create new objects of the given class
129            bool bCreatedOneObject_;                    //!< True if at least one object of the given type was created (used to determine the need of storing the parents)
130            static int hierarchyCreatingCounter_s;      //!< Bigger than zero if at least one Identifier stores its parents (its an int instead of a bool to avoid conflicts with multithreading)
131            static unsigned int classIDcounter_s;       //!< The number of unique Identifiers
132            unsigned int classID_;                      //!< The networkID to identify a class through the network
133    };
134
135
136    // ###############################
137    // ###     ClassIdentifier     ###
138    // ###############################
139    //! The ClassIdentifier is derived from Identifier and holds all class-specific functions and variables the Identifier cannot have.
140    /**
141        ClassIdentifier is a Singleton, which means that only one object of a given type T exists.
142        This makes it possible to store informations about a class, sharing them with all
143        objects of that class without defining static variables in every class.
144    */
145    template <class T>
146    class ClassIdentifier : public Identifier
147    {
148        public:
149            static ClassIdentifier<T>* registerClass(const IdentifierList* parents, const std::string& name, bool bRootClass);
150            static ClassIdentifier<T>* getIdentifier();
151            static void addObject(T* object);
152
153        private:
154            ClassIdentifier();
155            ClassIdentifier(const ClassIdentifier<T>& identifier) {} // don't copy
156            ~ClassIdentifier();
157
158            static ClassIdentifier<T>* pointer_s;       //!< A pointer to the singleton-object
159            ObjectList<T>* objects_;                    //!< The ObjectList, containing all objects of type T
160    };
161
162    template <class T>
163    ClassIdentifier<T>* ClassIdentifier<T>::pointer_s = NULL; // Set the static member variable pointer_s to zero
164
165    /**
166        @brief Constructor: Create the ObjectList.
167    */
168    template <class T>
169    ClassIdentifier<T>::ClassIdentifier()
170    {
171        this->objects_ = new ObjectList<T>;
172    }
173
174    /**
175        @brief Destructor: Delete the ObjectList, set the singleton-pointer to zero.
176    */
177    template <class T>
178    ClassIdentifier<T>::~ClassIdentifier()
179    {
180        delete this->objects_;
181        this->pointer_s = NULL;
182    }
183
184    /**
185        @brief Registers a class, which means that the name and the parents get stored.
186        @param parents An IdentifierList, containing the Identifiers of all parents of the class
187        @param name A string, containing exactly the name of the class
188        @param bRootClass True if the class is either an Interface or BaseObject itself
189        @return The ClassIdentifier itself
190    */
191    template <class T>
192    ClassIdentifier<T>* ClassIdentifier<T>::registerClass(const IdentifierList* parents, const std::string& name, bool bRootClass)
193    {
194#if HIERARCHY_VERBOSE
195        std::cout << "*** Register Class in " << name << "-Singleton.\n";
196#endif
197
198        // It's a singleton, so maybe we have to create it first
199        if (!pointer_s)
200        {
201#if HIERARCHY_VERBOSE
202            std::cout << "*** Register Class in " << name << "-Singleton -> Create Singleton.\n";
203#endif
204            pointer_s = new ClassIdentifier();
205        }
206
207        // Check if at least one object of the given type was created
208        if (!pointer_s->bCreatedOneObject_)
209        {
210            // If no: We have to store the informations and initialize the Identifier
211
212#if HIERARCHY_VERBOSE
213            std::cout << "*** Register Class in " << name << "-Singleton -> Initialize Singleton.\n";
214#endif
215            pointer_s->name_ = name;
216            Factory::add(name, pointer_s); // Add the Identifier to the Factory
217
218            if (bRootClass)
219                pointer_s->initialize(NULL); // If a class is derived from two interfaces, the second interface might think it's derived from the first because of the order of constructor-calls. Thats why we set parents to zero in that case.
220            else
221                pointer_s->initialize(parents);
222        }
223
224        return pointer_s;
225    }
226
227    /**
228        @returns the Identifier itself
229    */
230    template <class T>
231    ClassIdentifier<T>* ClassIdentifier<T>::getIdentifier()
232    {
233        if (!pointer_s)
234        {
235#if HIERARCHY_VERBOSE
236            std::cout << "*** Create Singleton.\n";
237#endif
238            pointer_s = new ClassIdentifier();
239        }
240
241        return pointer_s;
242    }
243
244    /**
245        @brief Adds an object of the given type to the ObjectList.
246        @param object The object to add
247    */
248    template <class T>
249    void ClassIdentifier<T>::addObject(T* object)
250    {
251#if HIERARCHY_VERBOSE
252        std::cout << "*** Added object to " << ClassIdentifier<T>::getIdentifier()->getName() << "-list.\n";
253#endif
254        object->getMetaList().add(ClassIdentifier<T>::getIdentifier()->objects_, ClassIdentifier<T>::getIdentifier()->objects_->add(object));
255    }
256
257
258    // ###############################
259    // ###   SubclassIdentifier    ###
260    // ###############################
261    //! The SubclassIdentifier acts almost like an Identifier, but has some prerequisites.
262    /**
263        You can only assign Identifiers that belong to a class of at least B (or derived) to a SubclassIdentifier<T>.
264        If you assign something else, the program aborts.
265        Because we know the minimal type, a dynamic_cast is done, which makes it easier to create a new object.
266    */
267    template <class T>
268    class SubclassIdentifier
269    {
270        public:
271            /**
272                @brief Constructor: Automaticaly assigns the Identifier of the given class.
273            */
274            SubclassIdentifier()
275            {
276                this->identifier_ = ClassIdentifier<T>::getIdentifier();
277            }
278
279            /**
280                @brief Overloading of the = operator: assigns the identifier and checks its type.
281                @param identifier The Identifier to assign
282                @return The SubclassIdentifier itself
283            */
284            SubclassIdentifier<T>& operator=(Identifier* identifier)
285            {
286                if (!identifier->isA(ClassIdentifier<T>::getIdentifier()))
287                {
288                    std::cout << "Error: Class " << identifier->getName() << " is not a " << ClassIdentifier<T>::getIdentifier()->getName() << "!\n";
289                    std::cout << "Error: SubclassIdentifier<" << ClassIdentifier<T>::getIdentifier()->getName() << "> = Class(" << identifier->getName() << ") is forbidden.\n";
290                    std::cout << "Aborting...\n";
291                    abort();
292                }
293                this->identifier_ = identifier;
294                return *this;
295            }
296
297            /**
298                @brief Overloading of the * operator: returns the assigned identifier.
299                @return The assigned identifier
300            */
301            Identifier* operator*()
302            {
303                return this->identifier_;
304            }
305
306            /**
307                @brief Overloading of the -> operator: returns the assigned identifier.
308                @return The assigned identifier
309            */
310            Identifier* operator->() const
311            {
312                return this->identifier_;
313            }
314
315            /**
316                @brief Creates a new object of the type of the assigned identifier and dynamic_casts it to the minimal type given by the SubclassIdentifier.
317                @return The new object
318            */
319            T* fabricate()
320            {
321                BaseObject* newObject = this->identifier_->fabricate();
322
323                // Check if the creation worked
324                if (newObject)
325                {
326                    // Do a dynamic_cast, because an object of type T is much better than of type BaseObject
327                    return dynamic_cast<T*>(newObject);
328                }
329                else
330                {
331                    // Something went terribly wrong
332                    if (this->identifier_)
333                    {
334                        std::cout << "Error: Class " << this->identifier_->getName() << " is not a " << ClassIdentifier<T>::getIdentifier()->getName() << "!\n";
335                        std::cout << "Error: Couldn't fabricate a new Object.\n";
336                        std::cout << "Aborting...\n";
337                    }
338                    else
339                    {
340                        std::cout << "Error: Couldn't fabricate a new Object - Identifier is undefined.\n";
341                        std::cout << "Aborting...\n";
342                    }
343
344                    abort();
345                }
346            }
347
348            /** @returns the assigned identifier. */
349            inline const Identifier* getIdentifier() const
350                { return this->identifier_; }
351
352            /** @returns true, if the assigned identifier is at least of the given type. @param identifier The identifier to compare with */
353            inline bool isA(const Identifier* identifier) const
354                { return this->identifier_->isA(identifier); }
355
356            /** @returns true, if the assigned identifier is exactly of the given type. @param identifier The identifier to compare with */
357            inline bool isDirectlyA(const Identifier* identifier) const
358                { return this->identifier_->isDirectlyA(identifier); }
359
360            /** @returns true, if the assigned identifier is a child of the given identifier. @param identifier The identifier to compare with */
361            inline bool isChildOf(const Identifier* identifier) const
362                { return this->identifier_->isChildOf(identifier); }
363
364            /** @returns true, if the assigned identifier is a parent of the given identifier. @param identifier The identifier to compare with */
365            inline bool isParentOf(const Identifier* identifier) const
366                { return this->identifier_->isParentOf(identifier); }
367
368        private:
369            Identifier* identifier_;        //!< The assigned identifier
370    };
371}
372
373#endif
Note: See TracBrowser for help on using the repository browser.