= Identifier = [[TOC]] == Description == The Identifier is a construct to identify the class of an object at runtime. All classes derived from OrxonoxClass have an Identifier. The Identifier additionally stores all objects of its class in a [wiki:ObjectListBase list], knows the name of the class, can have a [wiki:ClassFactory], knows all parents and children, stores [wiki:ConfigValueContainer config-values], [wiki:XMLPort XMLPort-containers], [wiki:ConsoleCommand console-commands] and provides several other functionalities. == Related classes == === Class Identifier === Every Identifier is in fact a [wiki:ClassIdentifier]. Identifier itself is the abstract baseclass of !ClassIdentifier. !ClassIdentifier is a template. This is needed to take care of the class-specific parts of the Identifier. Read the related Wiki-page for more information. === Subclass Identifier === The [wiki:SubclassIdentifier] is a class, that can act like an Identifier, but has a given base-class. Read the related Wiki-page for more information. == Usage == === Identifier of a class === You can get the Identifier of a given class with the macro '''Class('''''classname''''')'''. If you only know the string, so if the class isn't hardcoded, use the macro '''ClassByString('''''"classname"''''')'''. You have to include [wiki:CoreIncludes CoreIncludes.h] to use the macros. {{{ #include "core/CoreIncludes.h" // Variant 1: Identifier* identifierOfMyClass = Class(MyClass); // Variant 2: std::string classname = "OtherClass"; Identifier* identifierOfOtherClass = ClassByString(classname); }}} === Identifier of an object === To retrieve the Identifier of an object, use object->'''getIdentifier()''': {{{ OrxonoxClass* object = new SomeClass(); Identifier* identifierOfSomeClass = object->getIdentifier(); }}} === Name of a class === Use '''getName()''': {{{ OrxonoxClass* object = new SomeClass(); object->getIdentifier()->getName(); // returns "SomeClass" Class(MyClass)->getName(); // returns "MyClass" }}} === New classes === A new class that wants an Identifier must call RegisterObject(classname) in the constructor. A new interface has to inherit virtually from [wiki:OrxonoxClass] and call RegisterRootObject(interfacename) from in the constructor. Both macros are located in [wiki:CoreIncludes]. Read the related Wiki-page for more information. {{{ #include "core/CoreIncludes.h" // Constructor: MyClass::MyClass() { RegisterObject(MyClass); } }}} === Creating an object with fabricate() === You can create an object of a class represented by an Identifier by calling fabricate(). This function creates a new instance and returns a [wiki:BaseObject] pointer. '''Important''': If you have to cast the BaseObject-pointer to the real class, use '''dynamic_cast'''. {{{ Identifier* identifier = Class(MyClass); // Create an instance of MyClass: BaseObject* object = identifier->fabricate(); // Cast the pointer from BaseObject to MyClass: MyClass* object2 = dynamic_cast(object); }}} === Iterating through existing objects === '''getObjects()''' returns a pointer to an [wiki:ObjectListBase], containing all objects of the class. You can iterate through them with an [wiki:Iterator]: {{{ Identifier* identifier = Class(SomeClass); Iterator it = identifier->getObjects()->begin(); for (; it != identifier->getObjects()->end(); ++it) { it->callAFunction(); } }}} '''Important''': If you know at compiletime which class you want to iterate through, use [wiki:ObjectListIterator], because it's much faster: {{{ ObjectList::iterator it = ObjectList::begin(); for (; it != ObjectList::end(); ++it) { it->callAFunction(); } }}} === Comparison === Different Identifiers can be compared by using functions like isA(...) or isChildOf(...) to retrieve information about the class-hierarchy: * ''myidentifier'''''->isA('''''other''''')''': Compares the Identifier (''myidentifier'') with another Identifier (''other''). If ''myidentifier'' represents exactly the same or an inheriting class, the function returns true. * ''myidentifier'''''->isExactlyA('''''other''''')''': If ''myidentifier'' and ''other'' represent both the same class, the function returns true. * ''myidentifier'''''->isChildOf('''''other''''')''': If the class represented by ''myidentifier'' is a child of the class represented by ''other'', the function returns true. * ''myidentifier'''''->isDirectChildOf('''''other''''')''': Like isChildOf(...), but the class represented by ''myidentifier'' must be inherited directly without other classes between (class ''myidentifierclass'' : public ''otherclass''). * ''myidentifier'''''->isParentOf('''''other''''')''': If the class represented by ''myidentifier'' is a parent of the class represented by ''other'', meaning the other class is a child, the function returns true. * ''myidentifier'''''->isDirectParentOf('''''other''''')''': Like isParentOf(...), but the class represented by ''myidentifier'' must be a direct parent without other classes between (class ''otherclass'' : public ''myidentifierclass''). A more graphical explanation: {{{ #!html Green: If you call comparisonFunction(Class(MyClass)) on a green class, the function returns true.
Red: If you call comparisonFunction(Class(MyClass)) on a red class, the function returns false.

comparisionFunction is either isA, isExactlyA, isChildOf, isDirectChildOf, isParentOf or isDirectParentOf.

isA(MyClass): ParentOfParent | Parent | [MyClass | Child | ChildOfChild]
isExactlyA(MyClass): ParentOfParent | Parent | [MyClass] | Child | ChildOfChild
isChildOf(MyClass): ParentOfParent | Parent | MyClass | [Child | ChildOfChild]
isDirectChildOf(MyClass): ParentOfParent | Parent | MyClass | [Child] | ChildOfChild
isParentOf(MyClass): [ParentOfParent | Parent] | MyClass | Child | ChildOfChild
isDirectParentOf(MyClass): ParentOfParent | [Parent] | MyClass | Child | ChildOfChild
}}} === More Functions === '''Hierarchy''': Every Identifier provides sets of all parents and children: * getParents() * getChildren() * getDirectParents() * getDirectChildren() '''Identifiers''': There is also a static map containg all existing Identifiers: * Identifier::getIdentifierMap() * Identifier::getLowercaseIdentifierMap() '''ConfigValues''': Every Identifier stores the [wiki:ConfigValueContainer config-values] of the class: * getConfigValueMap() * getLowercaseConfigValueMap() * hasConfigValues() '''ConsoleCommands''': Also, Identifiers store the [wiki:ConsoleCommand console-commands] of the class: * getConsoleCommandMap() * getLowercaseConsoleCommandMap() * hasConsoleCommands() '''XMLPort Params''': The same for [wiki:XMLPort XMLPort params]: * getXMLPortParamMap '''XMLPort Objects''': And [wiki:XMLPort XMLPort objects]: * getXMLPortObjectMap == Examples == The following examples use the class-tree below. {{{ #!cpp Identifier* myidentifier = Class(A1); // Assigns the Identifier of A1 myidentifier->isA(Class(BaseObject)); // returns true myidentifier->isA(Class(A1)); // returns true myidentifier->isA(Class(A1B1)); // returns false myidentifier->isA(Class(A2)); // returns false Class(A3)->isA(Class(Interface1)); // returns true Class(A1B1)->isChildOf(Class(BaseObject)); // returns true Class(A1B1)->isChildOf(Class(A1)); // returns true Class(A1B1)->isDirectChildOf(Class(BaseObject)); // returns false Class(A1B1)->isDirectChildOf(Class(A1)); // returns true // Assigns the Identifier of the class with name "A2" std::string name = "A2"; Identifier* other = ClassByString(name); }}} {{{ #!cpp // Creates a new instance of A1 BaseObject* newobject = Class(A1)->fabricate(); // Creates a new instance of A1 and casts it to Interface1 Identifier* myidentifier = Class(A3); Interface1* newobject = dynamic_cast(myidentifier->fabricate()); }}} [[Image(code/doc/Core:testclass_interface_tree.gif)]] == Networking == Because Identifiers use pointers, they are not qualified for networking. It's possible to just send the classname and use the [wiki:Factory], but this is expensive. That's why there's a network ID. The network ID is an unsigned integer. You can retrieve an Identifier with a given network ID by using the macro ClassByID(int) (include [wiki:CoreIncludes CoreIncludes.h] to use it). It's not determined which network ID belongs to which Identifier. This changes from version to version and from system to system, depending on the number of existing classes and the code executed before main(). So ClassByID(5) might be different on each client. That's why the server has to synchronize the network ID's. You can retrieve the network ID of an Identifier with getNetworkID().[[br]] You can set the network ID of an Identifier with setNetworkID(int). After changing the network ID of an Identifier to ''newid'', there might be two Identifiers with the ID ''newid''. ClassByID(''newid'') will then return the changed Identifier and not the old one. Read the Wiki-page of [wiki:Factory] to get more information about how to iterate through all Identifiers. == Technical information == ---to come---