首页 > 其他 > 详细

unreal3对象管理模块分析

时间:2015-12-25 13:38:13      阅读:209      评论:0      收藏:0      [点我收藏+]

凡是稍微大一点的引擎框架,必然都要自己搞一套对象管理机制,如mfc、qt、glib等等,unreal自然也不例外。

究其原因,还是c++这种静态语言天生的不足,缺乏运行时类型操作功能,对于复杂庞大的逻辑层来说极为不便,查错和调优都很困难。

因此,这类框架自制对象管理模块的功能通常都包括:

1、运行时类型信息获取

  a、总共有哪些类,各自之间的继承关系怎样?简单来说,能否在运行时print一个类的继承链图出来。

  b、给你一个最基类指针,你能准确知道他实际是哪个子类的,有哪些方法、属性?

2、运行时类型创建及调用

  a、给你一个字符串名字,能否创建该类的对象?

  b、给你一些字符串方法或属性名,能否调用之?包括正确的参数和返回值处理

3、对象生命期的管理

  a、所有已创建的对象,是否都能追踪遍历?

  b、对象所占据内存,是否都有分门别类统计?

  c、对象是否支持gc?

4、各种杂项

  a、对象是否支持序列化?

  b、对象是否支持由脚本创建调用?

  c、对象是否支持设计时模式?也就是在编辑里呈现出另一种效果,可即时修改属性观察变化。

 

以上种种,通常都被各类框架不厌其烦的实现很多次了,即使在自己写的稍大一点的项目里,也或多或少做过类似的事,区别只是所谓商业级引擎,会做得更极致,更完善罢了。

而这些功能,其实都是java里的标配,在c++里却不得不各种重新发明轮子,这也说明c++在大工程架构方面先天不足,惟一的优势就是速度快,而游戏引擎极其注重性能,所以不得不在c++的基础上,重新添加大量类Java功能,以求性能和易用的结合。

 

在unreal3里,实现此模块的两个核心类分别是:

1、UObject:基本上是所有逻辑层类的祖基类,“一切皆是对象”,而每个对象必定属于一个类型,所以UObject里面有一个UClass* Class字段,就指向它的类型

2、UClass:这个就是表示一个类型的类,与UObject有大量的子类不同,UClass没有子类,它只是用不同的实例(携带不同属性)来表示各种类型。

举例来说,UObject的两个子类UCommandlet和UComponent,分别代表命令小工具和组件,它们各自有一个对应的UClass实例来描述自身类型信息。每一个Unrealscript类,也都有一个UClass实例与之对应。

这些UClass实例的创建过程也正好分类两类:

一是native类,即生成了C++头文件的,那么其中就包含相应的创建代码,相当于是手动写死链接的。

二是纯脚本类,它们的UClass实例是在加载Package时,由解析代码动态创建的。

 

UObject类型系统的实现:

在每个UObject子类的声明里,都有类似如下的宏:

DECLARE_ABSTRACT_CLASS(UCommandlet,UObject,0|CLASS_Transient,Core)

其中DECLARE_ABSTRACT_CLASS可能有DECLARE_CLASS、DECLARE_CASTED_CLASS、DECLARE_CLASS_INTRINSIC等变种,用于设定继承时的各类性质差别,其核心最后都转到【DECLARE_BASE_CLASS_LIGHTWEIGHT】:

#define DECLARE_BASE_CLASS_LIGHTWEIGHT( TClass, TSuperClass, TStaticFlags, TStaticCastFlags, TPackage ) public:     friend void AutoCheckNativeClassSizes##TPackage( UBOOL& Mismatch );     /* Identification */     enum {StaticClassFlags=TStaticFlags};     enum {StaticClassCastFlags=TStaticCastFlags};     private:     static UClass* PrivateStaticClass;     TClass & operator=(TClass const &);       public:     typedef TSuperClass Super;    typedef TClass ThisClass;    static UClass* GetPrivateStaticClass##TClass( const TCHAR* Package );     static void InitializePrivateStaticClass##TClass();     static UClass* StaticClass()     {         if (!PrivateStaticClass)         {             PrivateStaticClass = GetPrivateStaticClass##TClass( TEXT(#TPackage) );             InitializePrivateStaticClass##TClass();         }         return PrivateStaticClass;     }     void* operator new( const size_t InSize, UObject* InOuter=(UObject*)GetTransientPackage(), FName InName=NAME_None, EObjectFlags InSetFlags=0 )         { return StaticAllocateObject( StaticClass(), InOuter, InName, InSetFlags ); }     void* operator new( const size_t InSize, EInternal* InMem )         { return (void*)InMem; }

这里的关键:

1、static UClass* PrivateStaticClass; 这就是每个类型对应的那个UClass*实例了

2、static UClass* StaticClass(); 这个就是初始化函数,在程序启动时,每个包每个(native)类的该函数都会被调用,相当于注册,其中通过GetPrivateStaticClasssXXX来创建UClass*实例,然后调用InitializePrivateStaticClassXXX来初始化其属性。这两个函数的实现在后面说明。

3、重载了两个new操作符,也就是设定了其内存分配函数到自己的StaticAllocateObject中,里面执行大量跟踪统计逻辑。

 

然后在每个UObject子类的实现中,都有如下宏:

IMPLEMENT_CLASS(UCommandlet);

最后展开为:

#define IMPLEMENT_CLASS_LIGHTWEIGHT(TClass) \
    UClass* TClass::PrivateStaticClass = NULL;     UClass* TClass::GetPrivateStaticClass##TClass( const TCHAR* Package )     {         UClass* ReturnClass;         ReturnClass = ::new UClass         (             EC_StaticConstructor,             sizeof(TClass),             StaticClassFlags,             StaticClassCastFlags,             TEXT(#TClass) + 1 + ((StaticClassFlags & CLASS_Deprecated) ? 11 : 0),             Package,             StaticConfigName(),             RF_Public | RF_Standalone | RF_Transient | RF_Native | RF_RootSet | RF_DisregardForGC,             (void(*)(void*))TClass::InternalConstructor,             (void(UObject::*)())&TClass::StaticConstructor,             (void(UObject::*)())&TClass::InitializeIntrinsicPropertyValues         );         check(ReturnClass);         return ReturnClass;     }     /* Called from ::StaticClass after GetPrivateStaticClass */     void TClass::InitializePrivateStaticClass##TClass()     {         InitializePrivateStaticClass( TClass::Super::StaticClass(), TClass::PrivateStaticClass, TClass::WithinClass::StaticClass() );     }

这里就是GetPrivateStaticClasssXXX和InitializePrivateStaticClassXXX的定义了。

GetPrivateStaticClasssXXX里面:以【EC_StaticConstructor模式】(一般静态链接都是这种,如使用dll动态链接则会走另一套流程)new了一个UClass出来,注意这里new被重载过了所以会走上面的StaticAllocateObject来分配内存,最后其返回值会存在PrivateStaticClass静态变量,达到每个类一个UClass*实例的目的。

InitializePrivateStaticClassXXX里面:以父类的UClass、自己的UClass、外包类的UClass为参数,调用InitializePrivateStaticClass进行初始化,其内容也很简单:

void InitializePrivateStaticClass( class UClass* TClass_Super_StaticClass, class UClass* TClass_PrivateStaticClass, class UClass* TClass_WithinClass_StaticClass )
{
    /* No recursive ::StaticClass calls allowed. Setup extras. */
    if (TClass_Super_StaticClass != TClass_PrivateStaticClass)
    {
        TClass_PrivateStaticClass->SuperStruct = TClass_Super_StaticClass;
    }
    else
    {
        TClass_PrivateStaticClass->SuperStruct = NULL;
    }
    TClass_PrivateStaticClass->ClassWithin = TClass_WithinClass_StaticClass;
    TClass_PrivateStaticClass->SetClass(UClass::StaticClass());

    /* Perform UObject native registration. */
    if( TClass_PrivateStaticClass->GetInitialized() && TClass_PrivateStaticClass->GetClass()==TClass_PrivateStaticClass->StaticClass() )
    {
        TClass_PrivateStaticClass->Register();
    }
}

除了设置SuperStruct、ClassWithin等字段引用相应对象外,有趣的一句是setClass那里:它将自己设成了自己的Class。

前面说过“一切皆是对象”、“对象必有类型”,那么推出“类型也必是对象”,于是“类型对象也要有类型”,似乎要陷入死循环了,这里就用此种特殊的方式终止了循环:当一个对象的Class属性指向UClass::StaticClass()时,它自身必是一个UClass对象。

 

unreal3对象管理模块分析

原文:http://www.cnblogs.com/wellbye/p/5072239.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!