首页 > Personal > Game > 游戏引擎设计系列3-反射系统
2018
09-25

游戏引擎设计系列3-反射系统

反射是像C#这类高级语言的基本特性了,虽然会牺牲一定的性能,但是可以带来类似动态语言的好处,在运行时动态的生成操作对象,同时可以作为编辑器的基础,在图形界面同步修改显示对象的属性和变量。C++本身没有反射的支持,为了实现相关功能,需要使用宏定义,在类的声明和定义的同时定义相关TypeTraits,并组织TypeInfo。
interface TypeInfo {
enum Kind {
kVoid,
….
kString,
kIdentifier,
kClass,
};

const Identifier & GetName()
Kind GetTypeKind()
const Identifier & GetSuper()
bool HasSuper(const Identifier & name)
const TypeNameArray & GetInheritLine()
shared_ptr(PdeMemberInfo) GetMember(const Identifier & name)
const MemberInfoArray & GetMembers()
uint GetMemberCount()
shared_ptr(MemberInfo) GetMemberById(uint idx)
temp_ptr(IInvoke) GetConstructor()
void * QueryInterface(const Identifier & typeName, void * obj)

void SetSuper(const Identifier & name) // 生成TypeInfo时使用,用来设置基类
bool AddInterface(const Identifier & typeName, FN_QUERY_INTERFACE method) // 生成TypeInfo时使用,用来添加接口
bool AddMember(by_ptr(PdeMemberInfo) memberInfo) // 生成TypeInfo时使用,用来添加成员
static PDE_API temp_ptr(PdeTypeInfo) FromName(const Identifier & typeName)

static bool Register(const Identifier & typeName, by_ptr(TypeTraits) typetraits) // 注册TypeInfo和类的绑定关系,内部会调用TypeTraits的OnRegister
static PDE_API void Unregister(const Identifier & typeName) // 释放TypeInfo和类的绑定关系,
static PDE_API Identifier TypeNameFromRTTI(const class type_info & typeinfo)
static PDE_API shared_ptr(void) CreateInstance(const Identifier & typeName, IArguments & args) // 生成对象

Identifier Name;
Identifier SuperName;
TypeNameArray InheritLine;
HashSet MemberSet;
MemberArray Members;
HashSet InterfaceArray;
SharedPtr TypeTraits;
SharedPtr Constructor;
};

interface MemberInfo {
enum Kind {
kField,
kProperty,
kEvent,
kMethod,
kStaticMethod,
kConstructor,
kOperator,
kEnumItem,
};
const Identifier & GetName()
const Identifier & GetDeclaringType()
Kind MemberKind()
SharedPtr ToDelegate(by_ptr(void) object)
SharedPtr ToGetter(by_ptr(void) object)
SharedPtr ToSetter(by_ptr(void) object)
};

interface MethodInfo : public MemberInfo {
hared_ptr(void) Invoke(IArguments & args)
};

interface ConstructorInfo : public MethodInfo{};
interface OperatorInfo : public MethodInfo{};

interface FieldInfo : public MemberInfo {
bool GetValue(by_ptr(void) object, out_ptr(void) value)
bool SetValue(by_ptr(void) object, by_ptr(void) value)
const Identifier & GetFieldType()
};

interface PEnumItemInfo : public MemberInfo {
uint GetValue()
};

interface PPropertyInfo : public MemberInfo {
bool CanRead()
bool CanWrite()
const Identifier & GetPropertyType()
bool GetValue(by_ptr(void) object, out_ptr(void) value)
bool SetValue(by_ptr(void) object, by_ptr(void) value)
};

interface EventInfo : public MemberInfo {
const Identifier & GetArgumentType() = 0;
void Fire(by_ptr(void) object, by_ptr(void) arg) = 0;
uint Subscribe(by_ptr(void) object, by_weak_ptr(IDelegate) callback)
void Remove(by_ptr(void) object, by_weak_ptr(IDelegate) callback)
void Clear(by_ptr(void) object)
};

/// 实际的MemberInfo实现
template class RuntimeMethodInfo : public MethodInfo, public ChangeTypeName {
Identifier Name;
shared_ptr(StaticMemberDelegate) Func;
}
….
template class RuntimePropertyInfo : public PropertyInfo {
typedef GET_TYPE (C::*FN_GET)();
typedef void (C::*FN_SET)(SET_TYPE);
Identifier Name;
shared_ptr(StaticMemberDelegate) Getter;
shared_ptr(StaticMemberDelegate) Setter;
}

/// TypeTraits
interface ITypeTraits{
void OnRegister(by_ptr(TypeInfo) type) = 0;
void OnUnregister(by_ptr(TypeInfo) type) = 0;
PTypeInfo::Kind GetTypeKind() = 0;
};
template struct TypeTraits : public ITypeTraits;
template struct TypeTraitsBase : public TypeTraits
{
typedef T Self;
TypeInfo::Kind GetTypeKind() { return k; }
void OnRegister(by_ptr(TypeInfo) type) // 在这个函数内部注册需要添加的相关MemberInfo
void OnUnregister(by_ptr(eTypeInfo) type)
};

template struct TypeTraitsRegister
{
TypeTraitsRegister() { TypeInfo::Register(TYPE_NAME(T), ptr_new TT); } // 会调用TypeInfo的Register
~TypeTraitsRegister() { TypeInfo::Unregister(TYPE_NAME(T)); } // 会调用TypeInfo的Register
};

interface IArguments
{
shared_ptr(void) Argument(int idx, const Identifier & typeName)
int ArgumentCount() = 0;
};

interface IInvoke
{
shared_ptr(void) Invoke(IArguments & args) = 0;
int ParameterCount() = 0;
const Identifier & ParameterType(int idx) = 0;
};

通过M4推导IDelegate
template interface IDelegate;
….
template interface IDelegate : IInvoke
{
typedef RT (*FUNC)(P1);
typedef RT RT;
enum { ARG_COUNT = 1 };
typedef P1 ARG1;
typedef typename to_param_type::result PARAM1;
RT operator ()(PARAM1 p1) = 0;
};
这部分可以使用std::bind和std::function替换。

同时,相应的变量使用时需要进行打包和解包
template struct basic_boxing {
static inline shared_ptr(T) ByValue(const T & value) { return ptr_new T(value); }
static inline shared_ptr(T) ByReference(const T * value) { return ptr_new_reference (value); }
};

template struct referenced_boxing {
static inline shared_ptr(T) ByValue(const T & value) { return ptr_new_reference (value); }
static inline shared_ptr(T) ByReference(const T & value) { return ptr_new_reference (value); }
};

template struct ptr_boxing {
static inline shared_ptr(T) ByValue(const BasePtr & value) { return shared_ptr(T)(value); }
static inline shared_ptr(T) ByReference(const BasePtr & value) { return shared_ptr(T)(value); }
};

template struct referenced_unboxing {
typedef T & result;
static inline T & Unboxing(by_ptr(T) value) { return value.ToReference(); }
};

templatestruct pointer_unboxing {
typedef T * result;
static inline T * Unboxing(by_ptr(T) value) { return value.ToPointer(); }
};

template struct ptr_unboxing {
typedef temp_ptr(T) result;
static inline temp_ptr(T) Unboxing(by_ptr(T) value) { return value; }
};

template struct select_boxing {
typedef typename pde_template::remove_all::result T;
typedef typename pde_template::select< pde_template::can_cast_to::result,
referenced_boxing,
typename pde_template::select< pde_template::can_cast_to::result>>::result,
ptr_boxing::result>,
typename pde_template::select< pde_template::can_cast_to::result,
referenced_boxing,
basic_boxing
>::result
>::result
>::result result;
};

template struct select_unboxing {
typedef typename pde_template::remove_all::result RT;
typedef typename pde_template::select< pde_template::can_cast_to::result>>::result,
ptr_unboxing::result>,
typename pde_template::select< pde_template::is_pointer::result,
pointer_unboxing,
referenced_unboxing
>::result
>::result result;
};

template struct Boxing : public select_boxing::result, public select_unboxing::result {};

templatestatic void * offset_callback(void * obj) {
return static_cast(obj) + offset;
}

template static void * offset_ptr_callback(void * obj) {
return *reinterpret_cast(static_cast(obj) + offset);
}

template static void * cast_callback(void * obj) {
return (TO*)(FROM*)obj;
}

#define TYPE_VARNAME(l) TT_REGISTER_ ## l
#define DEFINE_TYPE_ENUM(t) template<> struct TypeTraits : public TypeTraitsBase
#define DEFINE_TYPE_CLASS(t) template<> struct TypeTraits : TypeTraitsBase
#define DEFINE_TYPE_CLASS_AS(t, c) struct c : public TypeTraits
#define REGISTER_TYPE(type) static TypeTraitsRegister> TYPE_VARNAME(__LINE__);
#define REGISTER_TYPE_AS(type, c) static TypeTraitsRegister TYPE_VARNAME(__LINE__);

#define ADD_PROPERTY_R(name) type->AddMember(NewRuntimePropertyInfo(#name, &Self::Get##name));
#define ADD_PROPERTY_W(name) type->AddMember(NewRuntimePropertyInfo(#name, &Self::Set##name));
#define ADD_PROPERTY_RW(name) type->AddMember(NewRuntimePropertyInfo(#name, &Self::Get##name, &Self::Set##name));
#define ADD_METHOD(name) type->AddMember(NewRuntimeMethodInfo(#name, &Self::name));
#define ADD_METHOD_AS(name, func) type->AddMember(NewRuntimeMethodInfo(#name, func));
#define ADD_STATIC_METHOD(name) type->AddMember(NewRuntimeStaticMethodInfo(#name, &Self::name));
#define ADD_STATIC_METHOD_AS(name, func) type->AddMember(NewRuntimeStaticMethodInfo(#name, func));
#define ADD_EVENT(name) type->AddMember(NewRuntimeEventInfo(#name, &Self::name));
#define ADD_FIELD(name) type->AddMember(NewRuntimeFieldInfo(#name, &reinterpret_cast(NULL)->name));
#define ADD_CONSTRUCTOR(func) type->AddMember(NewRuntimeConstructorInfo(“.ctor”, func));
#define ADD_DEFAULT_CONSTRUCTOR() type->AddMember(NewRuntimeConstructorInfo(“.ctor”, &Core::RuntimeDefaultConstructor));
#define ADD_OPERATOR(name, func) type->AddMember(NewRuntimeOperatorInfo(name, func));
#define ADD_ENUM_ITEM(name, value) type->AddMember(NewRuntimeEnumItemInfo(name, value));
#define ADD_ENUM_CONSTRUCTOR() type->AddMember(NewRuntimeConstructorInfo(“.ctor”, &Core::RuntimeEnumConstructor));

#define OFFSET_OF(strct, x) ((size_t)(&((strct *) NULL)->x))

#define ADD_INTERFACE(interfaceType, callback) type->AddInterface(TYPE_NAME(interfaceType), callback);
#define ADD_INTERFACE_MEMBER(interfaceType, member) type->AddInterface(PTYPE_NAME(interfaceType), &offset_callback);
#define ADD_INTERFACE_MEMBER_PTR(interfaceType, member) type->AddInterface(TYPE_NAME(interfaceType), &offset_ptr_callback);
#define ADD_INTERFACE_CAST(interfaceType) type->AddInterface(TYPE_NAME(interfaceType), &cast_callback);
#define ADD_SUPER(superType) type->SetSuper(TYPE_NAME(superType))

一个反射对象的例子如下
interface IGuiSystem {
shared_ptr(Gui::IDesktop) CreateGsDesktop(by_ptr(Graphics::GsScreen) screen) = 0;
GetSystemDesktop() = 0;
};

class GuiSystem : public IGuiSystem {
}

DEFINE_PDE_TYPE_CLASS(GuiSystem) {
void OnRegister(by_ptr(PdeTypeInfo) type) {
ADD_SUPER(IGuiSystem);
ADD_INTERFACE_CAST(IModule);
}
};
REGISTER_PDE_TYPE(GuiSystem);

DEFINE_PDE_TYPE_CLASS(IGuiSystem)
{
void OnRegister(by_ptr(PdeTypeInfo) type)
{
ADD_METHOD(CreateGsDesktop);
ADD_METHOD(GetSystemDesktop);
}
};
REGISTER_PDE_TYPE(IGuiSystem);

到此反射系统就介绍完了。

最后编辑:
作者:wy182000
这个作者貌似有点懒,什么都没有留下。