反射是像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
MemberArray Members;
HashSet
SharedPtr
SharedPtr
};
interface MemberInfo {
enum Kind {
kField,
kProperty,
kEvent,
kMethod,
kStaticMethod,
kConstructor,
kOperator,
kEnumItem,
};
const Identifier & GetName()
const Identifier & GetDeclaringType()
Kind MemberKind()
SharedPtr
SharedPtr
SharedPtr
};
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
void Remove(by_ptr(void) object, by_weak_ptr(IDelegate
void Clear(by_ptr(void) object)
};
/// 实际的MemberInfo实现
template
Identifier Name;
shared_ptr(StaticMemberDelegate
}
….
template
typedef GET_TYPE (C::*FN_GET)();
typedef void (C::*FN_SET)(SET_TYPE);
Identifier Name;
shared_ptr(StaticMemberDelegate
shared_ptr(StaticMemberDelegate
}
/// TypeTraits
interface ITypeTraits{
void OnRegister(by_ptr(TypeInfo) type) = 0;
void OnUnregister(by_ptr(TypeInfo) type) = 0;
PTypeInfo::Kind GetTypeKind() = 0;
};
template
template
{
typedef T Self;
TypeInfo::Kind GetTypeKind() { return k; }
void OnRegister(by_ptr(TypeInfo) type) // 在这个函数内部注册需要添加的相关MemberInfo
void OnUnregister(by_ptr(eTypeInfo) type)
};
template
{
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
….
template
同时,相应的变量使用时需要进行打包和解包
template
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
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
static inline shared_ptr(T) ByValue(const BasePtr
static inline shared_ptr(T) ByReference(const BasePtr
};
template
typedef T & result;
static inline T & Unboxing(by_ptr(T) value) { return value.ToReference(); }
};
template
typedef T * result;
static inline T * Unboxing(by_ptr(T) value) { return value.ToPointer(); }
};
template
typedef temp_ptr(T) result;
static inline temp_ptr(T) Unboxing(by_ptr(T) value) { return value; }
};
template
typedef typename pde_template::remove_all
typedef typename pde_template::select<
pde_template::can_cast_to
referenced_boxing
typename pde_template::select<
pde_template::can_cast_to
ptr_boxing
typename pde_template::select<
pde_template::can_cast_to
referenced_boxing
basic_boxing
>::result
>::result
>::result result;
};
template
typedef typename pde_template::remove_all
typedef typename pde_template::select<
pde_template::can_cast_to
template
template
return static_cast
}
template
return *reinterpret_cast
}
template
return (TO*)(FROM*)obj;
}
#define TYPE_VARNAME(l) TT_REGISTER_ ## l
#define DEFINE_TYPE_ENUM(t) template<> struct TypeTraits
#define DEFINE_TYPE_CLASS(t) template<> struct TypeTraits
#define DEFINE_TYPE_CLASS_AS(t, c) struct c : public TypeTraits
#define REGISTER_TYPE(type) static TypeTraitsRegister
#define REGISTER_TYPE_AS(type, c) static TypeTraitsRegister
#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
#define ADD_METHOD_AS(name, func) type->AddMember(NewRuntimeMethodInfo
#define ADD_STATIC_METHOD(name) type->AddMember(NewRuntimeStaticMethodInfo
#define ADD_STATIC_METHOD_AS(name, func) type->AddMember(NewRuntimeStaticMethodInfo
#define ADD_EVENT(name) type->AddMember(NewRuntimeEventInfo(#name, &Self::name));
#define ADD_FIELD(name) type->AddMember(NewRuntimeFieldInfo
#define ADD_CONSTRUCTOR(func) type->AddMember(NewRuntimeConstructorInfo
#define ADD_DEFAULT_CONSTRUCTOR() type->AddMember(NewRuntimeConstructorInfo
#define ADD_OPERATOR(name, func) type->AddMember(NewRuntimeOperatorInfo
#define ADD_ENUM_ITEM(name, value) type->AddMember(NewRuntimeEnumItemInfo
#define ADD_ENUM_CONSTRUCTOR() type->AddMember(NewRuntimeConstructorInfo
#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);
到此反射系统就介绍完了。
- 本文固定链接: http://www.wy182000.com/2018/09/25/游戏引擎设计系列3-反射系统/
- 转载请注明: wy182000 于 Studio 发表