关于VCF(Visual Component Framework)(2)
在VCF中,与RTTI相关的文件如下:
1、Property.h 属性的定义,包括事件属性的定义
2、Method.h 方法的定义,包括方法的参数定义
3、Field.h 字段的定义
4、Class.h、Class.Cpp 类RTTI的定义
5、InterfaceClass.h、InterfaceClass.Cpp 接口类和实现类的定义
6、ClassInfo.h 定义类定义时的宏操作
7、VCFRTTIImpl.h 类定义的具体实现类
8、ClassRegistry.h、ClassRegistry.Cpp 全局性的插入和记录整个系统中类RTTI信息
9、VariantData.h、VariantData.Cpp 定义VariantData数据结构,类似于VB的Variant变量
10、Enum.h 定义枚举型属性的枚举
一、Property的功能分析
Property提供一种对对象的读写操作方式,通过Property定义,用户可以采用如下方式访问对象:
Obj.GetValue("属性1");
Obj.SetValue("属性1",100);
在VCF中,Property被定义为抽象类,其定义中包括如下成员:



























1、Property只是一个接口类,其具体实现由继承子类完成,这是一种比较好的定义属性的方法,因为属性的操作、特别是属性的类型是很多的,如果在此实现Property的所有功能,将会严重限制Property的功能扩展;
2、从对集合型属性的处理来看,作者对设计模式的理解是比较深的,此处可以看作是Composite模式的一种特殊应用,对集合属性的操作则使用了Iterator模式,且定义了一种对序列型容器的通用遍历方法;
3、定义的value_是一个属性读写的缓冲区,即对同一类的所有对象,都是通过value_交换数据,value_被定义成一个VariantData,可以包含系统中使用的所有类型数据,但这存在一个问题,在多线程中,这是不安全的,不知VCF在程序的其它部分是否会对多线程模式下作特别处理;
二、EventProperty的功能分析
所谓Event,即事件,事件包括三个方面:事件的发生者、事件的处理者、事件本身的数据。举例说明:在控件中,针对鼠标移动,可以定义一个"OnMouseMove"事件处理过程。在此,控件是事件的发生者,OnMouseMove的处理对象和处理函数是事件的处理者,移动的数据和是否按下Ctrl键等,则是事件的本身。
在VCF中,EventProperty被定义为抽象类,其定义中包括如下成员:









三、Method的功能分析
所谓Method,即方法,提供一种对象功能调用的机制,定义了方法,对对象的操作可以如下进行:
Obj.Method1(Para1,Para2);
以下是Method的成员定义:























byte ArgTypes_[6];
四、InterfaceClass的功能分析
Iterface和ImplementedInterface分别定义了接口和接口实现,主要用来封装COM接口,比较简单,不再说明
五、Field的功能分析
比较简单,不再说明
六、Class的功能分析
待续......
七、类RTTI的声明过程
待续......
八、类RTTI的注册过程
待续......
九、VariantData的功能分析
待续......
十、总体分析
1、关于VariantData
为了提供对不同数据的访问接口,VCF中定义了VariantData数据类型,其定义类似于VB中的Variant类型,但类型没有VB中那么丰富,且其对String是单独处理,个人觉得,这种对String的单独处理是一种不得已而为之的处理,因为在VCF中,String被定义为一种std::basic_string<w_char>的简单封装,没有自动回收机制,因此,不能与其它简单数据(如int)同样处理。但应该会有一种和谐的处理方法的,上次在网上看到一个名为CSDTString的类,它是对STL中字符串类的仿MFC的CString的封装,过几天要仔细看看,看是否能用在此处。
2、关于RTTI的声明过程
RTTI的声明过程,类似于MFC中对消息处理的封装,也是采用了一系列的宏,这样定义后,在类中声明属性和方法的格式如下所示:




这样的处理有优点也有缺点,其缺点不是说其编写方式(采用其它方法,也许其属性的编写方式会更长更难看),而是指其宏展开后的内容。其展开后,是一个嵌入在Object中的一个嵌入类,这个嵌入类在创建时,判断类的信息是否已在系统中注册,如果未注册,则将类、属性、方法等向系统注册。我目前尚未找到一种更好的处理方法,但能明显看出其在处理时有如下缺点:
A、类在每一次实例化时,都会产生一个嵌入类,虽然这个嵌入类是轻量级的;
B、嵌入类在判断是否注册,是向系统查询,是否存在这个类的注册信息,但作为类来说,完成可以有更简单的方法来判断其是否已向系统注册过,只需要一个静态标志即可;
另外,我好象在《C++编程新思维》一书中看到,所有具有这种处理形式的类,完全可以通过模板来实现,具体方法还要查查书。
3、关于属性的改动事件
VCF中对属性的改动事件,是通过一个嵌入的委托类实现,思想很好,但似乎有设计漏洞:
A、只要属性被绑定到对象,则每一次set函数的调用,都会激发属性改变的事件,但如果set调用而并没有改变属性,这种事件是多余的;
B、每次改变事件发生时,它都会将改变前的值和改变后的值通过事件封装包发送到观察者,但很多情况下,改变后的值并不是送进来的值,比如:设置某控件的长度为123,但控制在得到123时,可能会对经修改,以处理对齐等功能,这样,改变的值可能是125而不是123;
C、属性的改变发生时,很可能会产生多个属性的联动,这种联动,如果采用每个属性的改变都会触发事件,则效率太低,如果不处理,则可能导致View和Document的不一致;
D、作为工控软件,应该要考虑到效率,所以,对属性的改变应该要增加批处理的功能;
4、关于String
VCF中,将String定义为Unicode字符值,因此,可以对中文进行处理,但在系统中,大量的函数都如下所示:
String GetName() { return name_;}
注意到它返回的是一个对象而不是引用,对性能肯定会有非常大的影响。就其原因,应该是系统的设计者想将String类型的数据作为一个简单类型的值,与其它简单类型的值同样处理。统一是一回事,性能又是一回事,一个用户是否选用某个系统,他很可能就因为其运行速度不行,或是程序的尺寸太大,而否决这个系统(想起了我在最后一家公司,那个伟大的7.0系统)。
5、关系性能
我分析VCF的过程中,我对其性能有非常大的疑问,因为其对RTTI的访问,都是通过字符串的查找进行的。
在一个典型的工控应用程序中,对RTTI的操作应该包括如下几个方面:
A、在组态环境下,通过属性来改变控件的值,如改变字体、颜色等。
这种应用情况下,系统是能准确知道那些类需要改变的(主要是选择列表),因此不需要通过对象的名称来访问对象。因此,在对象中,增加一个指向其RTTI信息的指针是非常必要的;
B、组态环境下,通过RTTI,从文件中读取数据,直接生成控件列表。
这种应用情况下,只能通过名字来查询,但应该可以通过一些特殊处理,对同一类型的对象只查一次表;
C、组态环境下,调用对象的属性、方法、事件等
这种应用情况下,对属性、方法、事件应该可能通过名称和序号两种方式访问,因此,增加属性、方法、事件的序号访问方法是必要的;
D、运行环境下,调用对象的属性、方法、事件等
这种应用情况的处理,决定了系统在运行时的性能,由于对象的属性、方法、事件等都是用户脚本程序自己编写的,用户在写脚本时,肯定是通过名称来处理的,如:
窗口1.控件2.宽=100
但由于我们同时也是脚本语言的设计者,完全可以通过预处理,将这种通过名称查询的语句解释成通过序号查询的功能调用,伪码如下:
系统.窗口[1].控件[2].SetWidth(100)
当然,由于用户可能在运行时增加脚本,因此,通过字符操作的属性处理也需要保留;
6、关于属性编辑
VCF的属性定义中,已将属性编辑的绝大部分内容定义了,但对属性的编辑,还可以参考Delphi的实现,提供自定义属性编辑器。
十一、总结
1、VCF是我看到的对RTTI处理最完整的开源项目;
2、其中对RTTI处理,有许多可取之处,特别是其对属性的封装,以及模板化的子类实现,都是非常好的思想;
3、也有许多值得推敲的地方,如果要将它应用到我的项目中,满足我的要求,需要改进重写;
4、VCF中除了RTTI外,还有其它部分的功能吸引我,准备在接下来的几天内,将那些内容也好好分析一下。
补充一点,我昨天提的AGG,在VCF中是作为第三方产品,在底层实现2D图形的处理,看来,AGG还真是好东西呀。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步