miércoles, 7 de marzo de 2012

Run-Time Type Information

Pues sigo con mi motor y lo que he hecho ahora es darle la capacidad a las clases de obtener información sobre su tipo. Esta técnica se puede activar por compilador pero es poco portable y muy ineficiente (por que se activa para todas las clases y con soporte para herencia múltiples). En mi caso lo hago restringiendo a herencia simple y solo para las clases que hereden de object. El UML es este:
Uso object como concentrador de utilidades que le voy dando a todo el resto de clases del motor, asi que rtti no se usa directamente sino a traves de objet. El codigo es este:
class Rtti
{
public:

    Rtti (const char* name, const Rtti* baseType);
    ~Rtti ();

    inline const char* GetName () const;
    inline bool IsExactly (const Rtti& type) const;
    bool IsDerived (const Rtti& type) const;

private:
    const char* m_name;
    const Rtti* m_baseType;
};
Como ves el nombre del tipo va en name y el tipo de la base es un puntero a una clase de tipo Rtti. Cuando queremos saber el tipo de una clase solo tenemos que hacer:
nombreClase::Rtti::GetName();
Y podemos saber si una clase es de un tipo asi:
if( objeto1::Rtti.IsExactly( objeto2::Rtti ) )
o tambien asi
if( objeto1.GetRttiType().IsExactly( objeto2.GetRttiType() )
Es en el objeto zelObject donde pongo el objeto Rtti para que lo hereden el resto de clases:
class zelObject
{
// Run-time type information.
public:
    virtual const Rtti& GetRttiType () const;
    bool IsExactly (const Rtti& type) const;
    bool IsDerived (const Rtti& type) const;
    bool IsExactlyTypeOf (const zelObject* object) const;
    bool IsDerivedTypeOf (const zelObject* object) const;
    static const Rtti TYPE;


// Abstract base class.  Construction and destruction.
protected:
    zelObject ();
public:
    virtual ~zelObject ();

};
Como ves el objeto Rtti se declara como static por que no hay necesidad de repetir esta información en cada instancia. Como cada clase tiene su propio objeto Rtti, el constructor escribirá en su propia instancia estatica el nombre de la clase. Para ayudar a que la declaracion sea menos tediosa incluyo estas macros:
//----------------------------------------------------------------------------
#define RTTI_DECLARATION \
public: \
    static const Rtti TYPE; \
    \
    virtual const Rtti& GetRttiType () const \
    { \
        return TYPE; \
    }
//----------------------------------------------------------------------------
#define RTTI_IMPLEMENTATION(nsname, baseclassname, classname) \
    const Rtti classname::TYPE(#nsname"."#classname, &baseclassname::TYPE)
//----------------------------------------------------------------------------
que delcaran el Rtti en cada clase como public(para sobreescribir en cada clase la declaración) e inicializar la variable estatica on el nombre de clase con su namespace, y el tipo. Pero para que tanto rollo? Entre otras cosas para poder hacer dynamic_cast sin tener que activar el rtti. Y que consigo con esto? Pues mi siguiento paso es la serialización, pero esto ya lo contaré más adelante.