前言
学以致用,通过QT框架的学习,一边实践,一边探索编程的方方面面.
参考书:<Qt 6 C++开发指南>(以下称"本书"),继承关系沿用本书说法:父类/子类,而非传统C++使用基类/派生类
标识说明:概念用粗体+倾斜.重点内容用(加粗黑体)---重点内容(红字)---重点内容(加粗红字),
本书原话内容用深蓝色标识,比较重要的内容用加粗倾斜下划线深蓝色标识
引入
Qt框架功能是本书的核心内容,本贴展开对元对象的理解
QMetaObject类(元对象类)
本书P49第4段:每个QObject及其子类的实例(对象)都有一个自动创建的元对象,元对象是QMetaObject类型的实例.元对象存储了类的实例所属类的各种元数据,包括类信息元数据、方法元数据、属性元数据等,所以,元对象实质上是对类的描述.
---解读:从以下几个方面来解读元对象和元数据:
1>什么是元数据?这里的元数据和<深入理解计算机系统>(原书第3版)P632中的文件元数据意思相同.表示每个类对象建立时的数据.包括了类方法,类属性,类构造函数,静态数据等内容
2>类对象元数据怎样实现的?笔者不清楚(如果C++提供了相应的接口,应该也可以访问).但可以分析得出结论---元数据实际上和文件元数据一样,由C++底层记录:每个类对象的属性和类型,方法的名称,参数和返回值,构造函数等信息,被放进了一个数据类型(假设名为MetaObject)中.
综合本书内容,元数据的大概形式是这样的,假设有一个名叫"DemoClass"的类
class DemoClass{
public:
void fun1(); //方法1
void fun2(); //方法2
DemoClass(); //构造函数
private:
SomeType1 st1; //属性1
SomeType2 st2; //属性2
}
对应的元数据类型表示为:
/*C++底层对元数据的表示*/
struct MetaObject{
vector<MetaClassInfo> mcis;
vector<MetaMethod> mms;
vector<MetaEnum> mes;
vector<MetaProperty> mps;
}
举个例子:MetaMethod类型里应该有些什么内容?他表示方法的元数据.vector表示了有n个方法,对应DemoClass类,mms中有2个MetaMethod对象,试着写出MetaMethod的类型定义:
/*只看意思,不保证准确*/
struct MetaMethod{
string return_type; //返回值类型
string method_name; //函数名称
vector<string> parameters; //参数类型名的集合
/*是否需要形参名未知*/
}
那么方法1的元数据---fun1()对应的元数据为
/*只看意思,不保证准确*/
/*方法1的元数据,返回值类型为空,函数名称为fun1,无参数*/
MetaMethod fun1={"void","fun1","NULL"}
意思比较明显了:QMetaObject封装了MetaObject类型对象---基于C++底层对类信息的表示
=============================内容分割线↓===================================
从C++底层对类信息的表示,继续思考:C++底层,或者机器层,是怎样理解类名,函数名,形参名等内容的?编译时需要用的语义分析---类名,函数名等字符串(姑且认为机器识别为char*类型),他一方面要在机器层面分配一个地址,一方面当地址内容和字符串对应上时,他知道是某个类对象或某个函数.
=============================内容分割线↑===================================
QObject和QMetaObject类型的关系
本书没有明确说明,他们可能是继承也可能是包含,笔者倾向于他们是"包含"关系
/*伪代码且不保证准确*/
//QMetaObject定义
class QMetaObject{
MetaObject mo;
}
//QObject定义
class QObject{
public:
QMetaObject qmo;
...
}
注意:表3-6的所有接口函数,要先生成元对象---调用表3-5中的第一个方法metaObject();
运行时类型信息
本书P50举了几个RTTI的例子,都包含在表3-5和表3-6的函数中,所以看一下即可.
本书P51的强制转换,和标准C++的强制转换类似:父类指针指向子类对象的可以转换.
属性系统
格式
本书P51讲了属性系统的格式,包括了类型、名称和值
宏Q_PROPERTY定义了一个值类型为type,名称为name的属性,用READ,WRITE关键字分别定义属性的读取、写入函数,还有一些其他关键字用于定义属性的一些操作特征.属性值的类型可以是QVariant支持的任何类型,也可以是自定义类型.
---解读:这里的属性和标准C++类型的属性做个对比---对比也是一种有效的学习方法
/*伪代码*/
class Demo{
private:
SomeType st;
....
}
Qt引入的属性系统,在普通C++属性基础上附加了操作信息,包括设置属性读写的函数,默认值,是否常量,是否发射信号,能否被子类重载,是否可以被用户编辑等等.想一想用普通C++也可以实现这些内容,Qt宏Q_PROPERTY封装了这些代码----所以读源码要把宏定义弄清楚
例子
本书P52:下面是QWidget类定义属性的一些例子.
/*原书示例*/
Q_PROPERTY(bool focus READ hasFocus)
Q_PROPERTY(bool enable READ isEnable WRITE setEnabled)
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)
属性读写
本书介绍了两种方法,推荐第一种直观明了,第二种比较复杂.第一种方法由对象调用.
注意:可读可写的属性通常有一个用于读取属性值的函数,函数名一般与属性名相同,还有一个用于设置属性值的函数,函数名一般是在属性前面加"set". ---不管哪一种语言基本上都这样写.
属性的读写,需要知道属性的数据类型.
属性元数据的使用
QMetaObject(属性元数据)对象记录了属性有关的操作信息---和属性设置时对应.使用方法如本书P52所示:
1.先获得组件元对象,再按照组件属性名称获得属性序号;
2.根据序号获得QMetaObject对象,此后按照QMetaObject对象函数获得属性信息.
动态属性
本书P53:如果属性名称不存在,就会为对象定义一个新得属性并设置属性值,这时定义得属性称为动态属性.
---解读:动态属性是添加的临时属性.
动态属性的设置有一个困惑之处:属性使用什么数据类型?本书的例子都是bool型.
附加的类信息
元对象系统还支持使用宏Q_CLASSINFO()在类中定义一些类信息,类信息有名称和值.
---解读:和动态属性一样,属于临时信息.
附加类信息的访问用三条代码实现:
1.获得对象的元对象---调用表3-5中的metaObject()
2.获得QMetaClassInfo对象---调用表3-6中的classInfo(int index),需传入索引号
3.调用name()返回类信息名称,调用value()返回类信息的值.
---动态属性和附加的类信息暂时没感觉有多大意义:如果设计完整,无需额外增加属性.
小结
元数据的一些解读.
元数据的内容和类信息相关的.感觉他的应用场景和信息安全有关.