Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

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

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