1. 程式人生 > >第三回 執行時類資訊(Runtime Class Information)

第三回 執行時類資訊(Runtime Class Information)

為清晰起見,省略了行末的\ )
#define DECLARE_CLASS(clss)
public:                                
    //類資訊,派生自基類CClass
    class CClass_##clss:public CClass  
    {                                  
    public:                            
        virtual void *New()        {   return _pool.Alloc();  }    
        virtual void Delete(void *p) {  _pool.Free((clss*)p);        }
        CMemPool<clss> _pool;//這個類的記憶體池
    };                                                               
    static CClass_##clss *_instantiate()                     
    {                      
        static CClass_##clss instance;      
        instance.SetName(#clss); //設定類的名稱,並註冊到全域性類資訊表格中去
        return &instance;                                                      
    }
    CClass *GetClass(){return _class;}
    static CClass_##clss *_class;  //靜態變數
*.然後再定義一個巨集,用來實現RtCIS:
#define IMPLEMENT_CLASS(clss)
    clss::CClass_##clss * clss::_class=clss::_instantiate();//定義並初始化靜態變數

*.再定義幾個巨集用來方便的使用這套系統:
#define Class_New(clss) (clss*)(clss::_class->New())
#define Class_Delete(p) (p)->GetClass()->Delete(p)
#define Class_NewByName(clssname) CClass::NewByName(clssname)
#define Class_GetName(p) (p)->GetClass()->GetName()
*.下面是一個例子,關於水果的:
在標頭檔案裡:
class CFruit
{
public:
    virtual CClass*GetClass()=0;
    //...
    //...
};
class CApple:public CFruit
{
public:
    DECLARE_CLASS(CApple);
    //...
    //...
};
class COrange:public CFruit
{
public:
    DECLARE_CLASS(COrange);
    //...
    //...
};
class CGrape:public CFruit
{
public:
    DECLARE_CLASS(CGrape);
    //...
    //...
};

在cpp檔案裡:
IMPLEMENT_CLASS(CApple);
IMPLEMENT_CLASS(COrange);
IMPLEMENT_CLASS(CGrape);
實際使用:
int main()
{
    CFruit* fruit1=Class_New(CApple);
    CFruit* fruit2=Class_New(COrange);
    CFruit* fruit3=Class_NewByName("CGrape");
    assert(std::string("CApple")==Class_GetName(fruit1));
    assert(std::string("COrange")==Class_GetName(fruit2));
    assert(std::string("CGrape")==Class_GetName(fruit3));

    Class_Delete(fruit1);
    Class_Delete(fruit2);
    Class_Delete(fruit3);
}

另外,這兩天在看havok的物理引擎,它的物件分配也採用了類似的方法,並且有一個比較好的特性就是對於某一個類,可以在每一個執行緒裡為它配備一個獨立的記憶體分配器(這樣就可以避免在記憶體分配程式碼里加鎖,有助於提高效率),比如

void thread1()
{
    CFruit* fruit1=Class_New(CApple);
    Class_Delete(fruit1);
}

void thread2()
{
    CFruit* fruit2=Class_New(CApple);
    Class_Delete(fruit2);
}
fruit1和fruit2是自動從兩個獨立的記憶體池裡分配出來的,我還沒看havok是怎麼實現的,不過應該不會太麻煩.希望將來有時間加這個feature.