Qt元对象系统(Meta-Object System)

        作为信号与槽机制的另一个得力干将,元对象系统不仅能支持信号与槽机制,还支持实时类型信息(RTTI)、动态属性系统等功能。元对象系统使我们可以在不知道对象类型的情况下与对象交互,表面意思很好理解,但是咱也不知道它有啥用啊?对吧?但是别急宝子们,且听我娓娓道来。

        首先,像我这样博爱的人,是一定会照顾到干货神教的同学们的,所有干货我都会加粗,其次,就是跳读者们(包括我)最爱的目录:

目录

玫瑰、神器和烛光晚餐

【QObject 是我爹】

自恋也疯狂(MOC)

我的24K钛合金红线去哪了?

丘比特?

丘比特套娃

女神通讯率


玫瑰、神器和烛光晚餐

特性 描述
信号和槽 支持对象之间的通信,并且自动跳过信号与槽对不上的连接
反射 在运行时查询对象的信息,属性动画和脚本绑定就是通过这个实现的
动态属性 在运行时添加新的属性,并储存在一个哈希表中

        要想知道它有啥用,我们就要彻底的、全面的、清晰的了解它,但凡它身着寸缕都是我们对它的不尊重!

        想要和一个人深入交流,首先要了解的就是TA的性格,同样的,想要和一个系统聊人生哲学,我们首先要知道它的脾性,想要使用元对象系统的功能那自然也是有条件的:

  • 类继承自QObject
  • 声明Q_OBJECT宏
  • 元对象编译器(MOC)

以上三个条件缺一不可,少一个它都不和你见面,就像玫瑰、神器和烛光晚餐一样重要。

【QObject 是我爹】

澄清一下,QObject 不是我爹,它是我们程序类的爹,请看如下代码:

class QtConnect : public QMainWindow
{
	Q_OBJECT

public:
	QtConnect(QWidget *parent = 0);
	~QtConnect() = default;

private:
	Ui::QtConnect* ui;
};

虽然这里看起来继承的是QMainWindow,但是QMainWindow是继承自QWidget,而QWidget则是继承的QObject,也就是说 QtConnect 是 QObject 它曾孙,不信你们看:

当然,我们也可以写一个类直接继承QObject,杜绝中间商赚差价,直接做 QObject 的儿子:


#include <QObject>

class StartPage : public QObject {
	Q_OBJECT

public:
	StartPage();
	~StartPage();

private:

};

这样的话我们就创建了一个既不是窗口,也不是控件的类,悄咪咪就继承了 QObject 的家产!

        而 Q_OBJECT 的用法和作用就很简单了,就像往脑门上贴一张纸,纸上写的【QObject 是我爹】,然后元对象系统就会为你服务,帮你干脏活累活。唯一要注意的就是放在类定义中就好,乱放的后果是很严重的!轻则元对象系统不鸟你,严重的话你的程序就要在二次元重生了。

        言归正传(来点干货,主打一个博爱),这里引用Qt官方文档中的一段话:

The Q_OBJECT macro is used to enable meta-object features, such as dynamic properties, signals, and slots.

You can add the Q_OBJECT macro to any section of a class definition that declares its own signals and slots or that uses other services provided by Qt's meta-object system.

意思是:Q_OBJECT 宏用于启用元对象功能,例如动态属性、信号和插槽。您可以将Q_OBJECT 宏添加到类定义的任何部分,该部分声明了自己的信号和插槽,或者使用 Qt 的元对象系统提供的其他服务。

        这里我们补充一点,它还有一个功能就是确保类与元对象编译器(MOC)同时工作,MOC会生成与类相关的元对象代码,信号和槽的连接等功能。

        再来看看 Q_OBJECT 宏不着寸缕的样子:

#define Q_OBJECT \
public: \
   QT_WARNING_PUSH \
   Q_OBJECT_NO_OVERRIDE_WARNING \
   static const QMetaObject staticMetaObject; \
   virtual const QMetaObject *metaObject() const; \
   virtual void *qt_metacast(const char *); \
   virtual int qt_metacall(QMetaObject::Call, int, void **); \
   QT_TR_FUNCTIONS \
private: \
   Q_OBJECT_NO_ATTRIBUTES_WARNING \
   Q_DECL_HIDDEN_STATIC_METACALL static void qt_static_metacall(QObject *,QMetaObject::Call, int, void **); \
   QT_WARNING_POP \
   
struct QPrivateSignal {}; \
QT_ANNOTATE_CLASS(qt_qobject,"")

可以看到【QObject 是我爹】这样一句话中竟然隐含了这么多的信息,一个静态 QMetaObject 变量,三个虚函数,一个QPrivateSignal结构体,一个静态 qt_static_metacall 函数,还有其余六个宏定义。这些定义我们很快就会用到,六个宏我们在其他文章中再讲,先来看看MOC是如何舔,哦不,如何配合工作的。

自恋也疯狂(MOC)

        MOC呢是一个比较自恋的家伙,所有他生成的元对象代码都会被打上moc的标签。耳听为虚,眼见为实,虽然我不会骗大家,但是以在下的文笔,难以写出它自恋的程度,不告诉大家的话,在下寝食难安啊!

        这样,我们先写一个 QtConnect 类,继承自 QObject ,文件名是:mainwindow.h/cpp,头文件内容如下(请同学们使用史上最强开源工具:CtrlCV):

#ifndef MAI
QtMeta-Object SystemQt 框架的核心特性之一,为实现高度动态和灵活的应用程序提供了基础。其主要功能和作用包括以下几个方面: ### 信号与槽机制 Qt 的信号与槽机制是对象间通信的核心机制,它允许对象在不耦合的情况下进行交互。例如,一个按钮可以发射一个信号,而一个其他对象可以连接到该信号并执行相应的操作。这种机制是通过元对象系统在运行时动态解析的,使得开发人员无需在编译时硬编码对象之间的依赖关系[^2]。 ### 运行时类型信息(RTTI) 元对象系统提供了运行时类型信息(Run-Time Type Information, RTTI),允许程序在运行时查询对象的类型信息。这种功能对于动态创建和管理对象非常有用。例如,可以使用 `qobject_cast` 在运行时安全地将一个 `QObject` 指针转换为更具体的子类类型[^2]。 ### 动态属性系统 Qt 的动态属性系统允许在运行时为对象添加和修改属性,而不需要在编译时定义这些属性。这使得应用程序可以动态地调整对象的行为和状态。例如,可以通过 `setProperty` 方法为对象设置属性,并通过 `property` 方法获取属性值[^2]。 ### 元对象编译器(Meta-Object Compiler, moc) QtMeta-Object Compiler(moc)是元对象系统的重要组成部分。它为每个继承自 `QObject` 的类生成额外的代码,以支持信号与槽、动态属性等功能。开发人员在类定义中使用 `Q_OBJECT` 宏来启用这些功能。moc 会根据这些宏生成相应的元对象代码,从而使得类能够利用 Qt 的动态特性。 ### 元方法和元属性 元对象系统支持通过元方法和元属性对类的功能进行描述。元方法可以是类的公共函数,而元属性则是类的可读写属性。这些信息可以通过 `metaObject()` 方法访问,并在运行时动态调用。这种机制为 Qt 的脚本化和动态调用提供了基础[^1]。 ### 实例代码 以下是一个简单的示例,展示了如何在 Qt 中使用信号与槽机制: ```cpp #include <QObject> #include <QDebug> class MyClass : public QObject { Q_OBJECT public: MyClass(QObject *parent = nullptr) : QObject(parent) {} signals: void mySignal(); public slots: void mySlot() { qDebug() << "Slot called!"; } }; int main(int argc, char *argv[]) { QObject obj; MyClass myObject; // 连接信号和槽 QObject::connect(&myObject, &MyClass::mySignal, &myObject, &MyClass::mySlot); // 发射信号 emit myObject.mySignal(); return 0; } ``` 在这个示例中,`MyClass` 继承自 `QObject` 并使用 `Q_OBJECT` 宏启用元对象功能。通过 `connect` 方法将 `mySignal` 信号连接到 `mySlot` 槽函数,并在发射信号时触发槽函数的执行。 ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值