导语
本文将深入Property的部分进行介绍,相比较[[reflectionfunctionimplement]],Property涉及的TagDispatch和中间过程更复杂,整体的实现需要一步一步来理清,我们还是从例子入手,从Property的注册和使用来展开整体的实现。
在上篇《C++反射:深入浅出剖析ponder库实现机制!》中我们对反射实现的整体做了相关的介绍,本篇将深入Property的部分进行介绍。
一、Property示例代码
//-------------------------------------//registercode//-------------------------------------__register_typeVector3("Vector3").constructor().constructordouble,double,double().property("x",Vector3::x).property("y",Vector3::y).property("z",Vector3::z));//-------------------------------------//usecode//-------------------------------------auto*metaClass=__type_offramework::math::Vector3();ASSERT_TRUE(metaClass!=nullptr);autoobj=runtime::CreateWithArgs(*metaClass,Args{1.0,2.0,3.0});ASSERT_TRUE(obj!=UserObject::nothing);constreflection::Property*fieldX=nullptr;metaClass-TryProperty("x",fieldX);ASSERT_TRUE(fieldX!=nullptr);doublex=fieldX-Get(obj).Todouble();ASSERT_DOUBLE_EQ(1.0,x);fieldX-Set(obj,2.0);x=fieldX-Get(obj).todouble();ASSERT_DOUBLE_EQ(2.0,x);
上面的代码分为两部分:
(一)注册的代码注册的代码通过__register_typeT()创建的ClassBuilder提供的。property(name,property)函数来完成对属性的注册。(二)使用的代码使用的代码,先获取到MetaClass,再从MetaClass中通过TryProperty()通过名字查询到对应的reflection::Property,然后我们可以通过Property的Get(),Set()方法来对对应UserObject对象的属性进行设置和获取。(三)整体文章的展开思路
我们的讲述会按照下面的顺序逐步展开:一些基础知识。
Property运行时的承载对象Property类。
编译期的注册机制。
不同的Property特化实现。
运行时获取值、设置值的具体过程。
二、基础知识
C++中的Property多以MemberObject的方式表达,MemberObject的类型和处理方式比较特殊。以framework::math::Vector3举例:
Vector3的成员变量定义如下:
classVector3{public:doublex;doubley;doublez;};
以下代码是用来获取成员变量y的:
//usingMemberType=double(framework::math::Vector3::*);usingMemberType=doubleframework::math::Vector3::*;MemberTypetmppy=framework::math::Vector3::y;framework::math::Vector3tmpvec(1.0,2.0,3.0);autotmpy=tmpvec.*tmppy;简单总结如下:
通过T(C::)或者TC::来表达成员变量的类型,如上例中的double(Framework::math::Vector3::)。
通过成员变量取地址的方式获取对应成员的地址,如上例中的framework::math::Vector3::y。
如上例中,可以通过tmpvec.tmppy这种获取方式来获取对应对象中的成员(获取的是tmpvec.y的值)。
正常如果不是实现反射,很少使用相关的特性。
三、运行时属性的表达-Property类
为了实现运行时Property,所有的Property需要进行类型擦除,以一致的外观进行组织和调用,framework中的Property实现如下(节选):classProperty:publicType{public:IdReturnname()const;ValueKindkind()const;virtualboolIsReadable()const;virtualboolIsWritable()const;ValueGet(constUserObjectobject)const;voidSet(constUserObjectobject,constValuevalue)const;inlineTypeIdtype_index()const{returntype_index_;}inlineautoimplement_type()const{returnimplement_type_;}protected:virtualValueGetValue(constUserObjectobject)const=0;virtualvoidSetValue(constUserObjectobject,constValuevalue)const=0;};
主要使用的是Get(),Set()两个方法,用于从UserObject中获取和设置指定Property的值。
四、依赖的核心机制
虽然Property整体的机制比较复杂,但核心依赖的机制实现比较简洁,主要依赖的是ValueBinder和ValueBinder2,以及与这两者基本一致的InternetRefBinder和InternetRefBinder2模板类。
(一)ValueBinder和ValueBinder2ValueBinder的实现如下图所示:上图中还有个依赖的Binding对象,具体的信息如下:
相关的Function和Member的Traits我们下文中会具体展开,本部分主要