понедельник, 9 августа 2010 г.

Аналог dynamic_cast и RTTI

Решил перепостить в свой блог подсказку, которую я писал на сайте Gamedev.ru (здесь), и заодно немного подправить

Простой аналог dynamic_cast и RTTI для тех, кто не хочет, по каким-либо религиозным причинам, использовать встроенный...

  1. class CType
  2. {
  3.   const CType*  mSuper;
  4.   const char*    mName;
  5. public:
  6.   CType( const CType* parent, const char* name ): mSuper(parent), mName(name) {}
  7.  
  8.   inline bool Is( const CType* objtype ) const
  9.   {
  10.     while( objtype && objtype != this )
  11.     {
  12.       objtype = objtype->mSuper;
  13.     }
  14.     return objtype == this;
  15.   }
  16.  
  17.   inline const char* GetName() const { return mName; }
  18. };
  19.  
  20. #define DECLARE_GET_TYPE(cls)      \
  21.     typedef cls  Self;    \
  22.     virtual const CType*  GetType() const { return &Type(); }
  23.  
  24. #define DECLARE_OBJECT(cls)    \
  25.     typedef Self  Super;    \
  26.     static inline const CType&  Type() { static const CType my_type( &cls::Super::Type(), #cls ); return my_type; }  \
  27.     DECLARE_GET_TYPE(cls)
  28.          
  29. #define DECLARE_ROOT_OBJECT(cls)            \
  30.     static inline const CType&  Type() { static const CType my_type( 0, #cls ); return my_type; } \
  31.     DECLARE_GET_TYPE(cls)             \
  32.     template <class T> static inline T* Cast( cls * obj )      \
  33.     {                \
  34.       return GET_CLASS_TYPE(T)->Is( GET_OBJECT_TYPE(obj) ) ? (T*)obj : NULL;  \
  35.     }                \
  36.     \
  37.     template <class T> static inline const T* Cast( const cls * obj )  \
  38.     {                \
  39.       return GET_CLASS_TYPE(T)->Is( GET_OBJECT_TYPE(obj) ) ? (T*)obj : NULL;  \
  40.     }
  41.  
  42. /////////////////////////////////////////////////////////////////////////////////
  43. #define GET_CLASS_TYPE(cls) (&cls::Type())
  44. #define GET_CLASS_TYPE_NAME(cls) (GET_CLASS_TYPE(cls)->GetName())
  45.  
  46. #define GET_OBJECT_TYPE(obj) (obj->GetType())
  47. #define GET_OBJECT_TYPE_NAME(obj) (GET_OBJECT_TYPE(obj)->GetName())
  48. /////////////////////////////////////////////////////////////////////////////////

пример использования

  1. #include <iostream>
  2.  
  3. class Object
  4. {
  5. public:
  6.   DECLARE_ROOT_OBJECT(Object)
  7.  
  8. };
  9.  
  10. class ChildObject : public Object
  11. {
  12. public:
  13.   DECLARE_OBJECT(ChildObject)
  14. };
  15.  
  16. class SecondChildObject : public ChildObject
  17. {
  18. public:
  19.   DECLARE_OBJECT(SecondChildObject)
  20. };
  21.  
  22. int main()
  23. {
  24.   const Object *o1 = new Object(), *o2 = new ChildObject(), *o3 = new SecondChildObject();
  25.   const ChildObject* derived = 0;
  26.   const SecondChildObject* secondderived = 0;
  27.  
  28.   std::cout<< "o1 is " << GET_OBJECT_TYPE_NAME( o1 ) << std::endl;
  29.   std::cout<< "o2 is " << GET_OBJECT_TYPE_NAME( o2 ) << std::endl;
  30.   std::cout<< "o3 is " << GET_OBJECT_TYPE_NAME( o3 ) << std::endl << std::endl;
  31.  
  32.   derived = Object::Cast<ChildObject>(o1);
  33.   std::cout<< "o1 is " << (derived == 0 ? "not ": "") << GET_CLASS_TYPE_NAME(ChildObject) << std::endl;
  34.   derived = Object::Cast<ChildObject>(o2);
  35.   std::cout<< "o2 is " << (derived == 0 ? "not ": "") << GET_CLASS_TYPE_NAME(ChildObject) << std::endl;
  36.   derived = Object::Cast<ChildObject>(o3);
  37.   std::cout<< "o3 is " << (derived == 0 ? "not ": "") << GET_CLASS_TYPE_NAME(ChildObject) << std::endl << std::endl;
  38.  
  39.  
  40.   secondderived = Object::Cast<SecondChildObject>(o1);
  41.   std::cout<< "o1 is " << (secondderived == 0 ? "not ": "") << GET_CLASS_TYPE_NAME(SecondChildObject) << std::endl;
  42.   secondderived = Object::Cast<SecondChildObject>(o2);
  43.   std::cout<< "o2 is " << (secondderived == 0 ? "not ": "") << GET_CLASS_TYPE_NAME(SecondChildObject) << std::endl;
  44.   secondderived = Object::Cast<SecondChildObject>(o3);
  45.   std::cout<< "o3 is " << (secondderived == 0 ? "not ": "") << GET_CLASS_TYPE_NAME(SecondChildObject) << std::endl << std::endl;
  46.  
  47.   return 0;
  48. }
  49.  

output:

o1 is Object
o2 is ChildObject
o3 is SecondChildObject

o1 is not ChildObject
o2 is ChildObject
o3 is ChildObject

o1 is not SecondChildObject
o2 is not SecondChildObject
o3 is SecondChildObject


Замечание: Данный метод не работает при наследовании от нескольких базовых классов...



* Подсветка синтаксиса http://quickhighlighter.com

суббота, 7 августа 2010 г.

Удобная работа с родительскими классами

Очень часто, при наследовании, хочется иметь удобный способ вызова функций родительского класса. Для этого можно завести пару дефайнов:

  1. #define DECLARE_ROOT_OBJECT(cls)    \
  2.     typedef cls  Self;    \
  3.  
  4. #define DECLARE_OBJECT(cls)    \
  5.     typedef Self  Super;    \
  6.     typedef cls Self;

Использовать так:

  1. class Base
  2. {
  3. public:
  4.     DECLARE_ROOT_OBJECT(Base)
  5.  
  6.     virtual void Foo();
  7. };
  8.  
  9. class Derived : public Base
  10. {
  11. public:
  12.     DECLARE_OBJECT(Derived)
  13.  
  14.     void Foo()
  15.     {
  16.         Super::Foo();
  17.     }
  18. };
Метод взят из обсуждения подсказки на сайте Gamedev.ru 

* Подсветка синтаксиса http://quickhighlighter.com