Qt 源码分析之元对象系统(一)
一、元对象系统
简单来说 Qt 元对象系统是对标准 C++ 的扩展。相比较其他高级语言java、python、php等,标准 C++ 为你做的工作实在是太少了,这样就使得开发人员写 C++ 很累,累的像 XXX 一样。特别是用 C++ 开发界面程序,那叫一个痛苦(这是针对大型软件)。
怎么办呢?既然标准不去做,那就让 Qt 来做吧,于是乎就诞生了 Qt 元对象系统。
一句话总结:Qt 元对象系统是为了方便程序开发,而对标准 C++ 做的扩展。
二、举例
比如我们用 C++ 写了一个类 CMathEx,这个类是对标准数学类的扩展,我们给这个类添加查找 3 个整数中最大值的函数,如下:
#define max(x, y) (x) > (y) ? (x) : (y)
class CMathEx
{
public:
CMathEx()
{
}
~CMathEx()
{
}
int Max(int a, int b, int c)
{
return max(max(a, b), c);
}
};
然后我们定义一个 CMathEx 类对象 m,就可以调用 Max 函数了,如下:
CMathEx m;
m.Max(1, 99, 88);
采用如上方式你写了 n 多年。人算不如天算啊,问题来了,随着你编写的软件系统越来越庞大、架构越来越复杂、类和类对象也越来越多,为了保持软件系统的可升级和可维护性,CTO 要求增加动态获取自定义类的类信息的功能,比如对象所属类的名字、类中有几个成员函数、类中有几个属性等等。
怎么办呢?只见你灵机一动,这还不简单,给我们自定义的类增加上一些接口就不就可以了吗。
经过 5 分钟改造后的CMathEx如下:
#define max(x, y) (x) > (y) ? (x) : (y)
class CMathEx
{
public:
CMathEx()
{
}
~CMathEx()
{
}
const char * ClassName()
{
return "CMathEx";
}
int Max(int a, int b, int c)
{
return max(max(a, b), c);
}
};
感觉自己真是聪明绝顶,这么简单就解决了 CTO 苦思冥想、夜不能寐的问题。兴致勃勃的你去软件系统里面查了查,发现大大小小一共有几千个类,哇塞,怎么办?
似乎你能想到的办法只要一个,就是一个类一个类的去修改。如果这样做整个软件系统从底层到上层要修改一遍,再加上修改后还需要测试,没有半年是搞不定的。
接下来怎么办?你也不知道,你也不敢问……
直到你遇到了 Qt 元对象系统,如同久旱逢甘霖呀。
重复的工作为什么要自己做呀,我们单独开发一个小工具 moc.exe ,让它读取要修改的文件,自动增加上我们想要扩展的函数接口,岂不妙哉!
到此相信你有很多个问号,不要着急往下看。
三、问题解答
问题 1、
细心的老鸟已经发现,为什么 Qt 元对象系统没有修改 xxxxxx.h xxxxxx.cpp 原始的两个文件,而是增加了一个moc_xxxxxx.cpp 新文件呢?
原因也不难想,如果修改了原始的文件,出了问题算谁的呢?Qt 为啥要去招惹这个麻烦呢(老鸟们都应该深有体会吧)。
问题 2、
增加一个接口不应该是同时修改 xxxxxx.h 和 xxxxxx.cpp 吗?
是的。因为增加的接口是统一的接口,所以 Qt 是通过宏来修改 xxxxxx.h ,举例说明:
原始的文件如下:
/*
CMathEx.h
*/
#define max(x, y) (x) > (y) ? (x) : (y)
class CMathEx
{
public:
CMathEx();
~CMathEx();
int Max(int a, int b, int c);
};
/*
CMathEx.cpp
*/
#include "CMathEx.h"
CMathEx::CMathEx()
{
}
CMathEx::~CMathEx()
{
}
int CMathEx::Max(int a, int b, int c)
{
return max(max(a, b), c);
}
修改流程如下:
1、首先定义一个宏
(如果是在 Qt 中,这个宏是 Q_OBJECT)
#define OBJECT_EX \
public: \
const char * ClassName(); \
2、在需要修改的类头文件中增加宏
/*
CMathEx.h
*/
#define max(x, y) (x) > (y) ? (x) : (y)
class CMathEx
{
OBJECT_EX
public:
CMathEx();
~CMathEx();
int Max(int a, int b, int c);
};
3、使用 moc.exe 处理包含宏的头文件
/*
moc_CMathEx.cpp
*/
#include "CMathEx.h"
const char * CMathEx::ClassName()
{
return "CMathEx";
}
四、总结
本篇文章简单介绍了 Qt 元对象系统的原理,具体实现细节还有很多,会陆续写出来分享,请大家点击关注