【元对象系统】

【元对象系统】,第1张

关键字

编译器,元对象系统,反射,信号槽

详解

c++中提到编译器,大家直观上就认为编译器就是把代码转化为二进制的工具。


这很容易让人产生误解,其实moc编译器的功能是把某些特殊的宏转化为c++代码。


Qt 的 moc 会完成以下工作:

  • Q_OBJECT宏展开后所声明的成员函数的成生实现moc_xxx.cpp代码;
  • 识别 Qt 中特殊的关键字,比如识别出 Q_PROPERTYQ_INVOKABLEslotsignals宏等。


这些关键字用于辅助moc识别信号函数和槽函数,而且必须放在头文件中:

// Qt4中为 protected. Qt5为支持connect函数指针写法, 定义为 public
#define signals public  
// slots被替换成空
#define slots
// emit被替换成空, 其作用仅仅是给qt的用户进行提示
#define emit

用于对信号和槽进行编号+命名

#define SLOT(a) "1"#a    #define SIGNAL(a) "2"#a

Q_OBJECT用于为自定义类添加一些函数声明,MOC编译器会为每个带有Q_OBJECT的头文件xxx.h自动生成moc_xxx.cpp,并在文件中实现Q_OBJECT中声明的函数。


QObject派生的含有 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, "")
  • staticMetaObject
    类的静态成员,存储当前类的元信息;
  • const QMetaObject *metaObject() const
    返回当前类的QMetaObject,即staticMetaObject成员;
  • void *qt_metacast(const char *)
    QObject::inherits直接调用,用于判断是否是继承自某个类。


    判断时,需要传入父类的字符串名称;

  • int qt_metacall(QMetaObject::Call, int, void **)
    调用函数回调,内部调用了qt_static_metacall函数;
  • static void qt_static_metacall(QObject *, QMetaObject::Call, int, void **)
    根据函数索引进行调用槽函数。


注意到有三个函数是虚函数,它们是QObject的虚函数成员,当我们在自定义对象中添加Q_OBJECT宏的时候,相当于重载了这三个虚函数。


信号槽

信号槽本质就是回调函数+发布订阅模式。


Qt为提供了5种类型的回调方式,如下:
Qt::AutoConnection 自动连接,根据sender和receiver是否在一个线程里来决定使用哪种连接方式,同一个线程使用直连,否则使用队列连接
Qt::DirectConnection 直连
Qt::QueuedConnection 队列连接
Qt::BlockingQueuedConnection 阻塞队列连接,顾名思义,虽然是跨线程的,但是还是希望槽执行完之后,才能执行信号的下一步代码
Qt::UniqueConnection 唯一连接

原理

从最简单的直连,了解信号槽的实现原理。



QObject中有一个用于存储信号和槽的数据结构:

//每一个信号与一个 QObjectPrivate::ConnectionList链表关联
class QObjectConnectionListVector : public QVector<QObjectPrivate::ConnectionList>
connect

connect构造了一个QObjectPrivate::Connection 对象,然后存储在了发送者对象的ConnectionList

signal调用流程

signal->QMetaObject::activate->qt_static_metacall->slot
QMetaObject::activate函数内部实根据ConnectionList查找得到信号对应的qt_static_metacall,然后一一调用槽函数。


反射

反射:是指在运行时,能获取任意一个类对象的所有类型信息、属性、成员函数等信息的一种机制。



元对象:是指用于描述另一个对象结构的对象。


使用 Qt 反射机制的条件

1、需要继承自 QObject 类,并需要在类之中加入 Q_OBJECT宏。



2、注册成员函数:若希望普通成员函数能够被反射,需要在函数声明之前加入
Q_INVOKABLE 宏。



3、注册成员变量:若希望成员变量能被反射,需要使用 Q_PROPERTY 宏。


原理

moc编译器会根据Q_OBJECT关键字,把类名存入staticMetaObject静态成员中;根据 Q_INVOKABLE把方法名存入staticMetaObject静态成员中;根据 Q_PROPERTY把属性名存入staticMetaObject静态成员中。



注意到staticMetaObject,它就是所谓的元对象,是静态成员,因此同一个类的所有对象共享一个元对象。


应用 类型识别

qobject_cast<>inherits()

修改属性值

QObject::setProperty()

动态IOC

QT的元对象系统,并不能直接通new "className"的方式创建对象,需要我们自己实现。


欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/langs/564005.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-04-03
下一篇 2022-04-03

发表评论

登录后才能评论

评论列表(0条)

保存