QT元对象系统和信号槽

初识QObject和QMetaObject

QObject是qt的一个核心基类
QMetaObject为一个元数据对象 MOC编译器可以为每个QObject派生类类基于Q_OBJECT宏生成代码
主要是定义对应的QMetaObject类对象和QObject子类的方法重写。

QMetaObject定义了QObject子类的元数据:类名称,信号信息(字符串,个数)和槽函数的执行函数体等等
MOC为某个QObject子类生成的代码中重写的const QMetaObject *MainWindow::metaObject() 方法就是返回相应定义的QMetaObject

例如创建一个最简单的应用程序
里面有一个继承自QMainwindow的mainwindow类,为其ui添加一个pushbutton,并增加btn的click槽函数。并且增加了一个名为sigTest的信号。

signals:
void sigTest();
private slots:
void on_pushButton_clicked();

经过moc编译的编译以后,我们可以看到moc_mainwindow.cpp中的代码

Moc编译器对QMetaObject和QObject的影响

生成了类型的字符串信息内容

static const qt_meta_stringdata_MainWindow_t qt_meta_stringdata_MainWindow = {
    {
QT_MOC_LITERAL(0, 0, 10), // "MainWindow"
QT_MOC_LITERAL(1, 11, 7), // "sigTest" moc编译器根据我们所添加的信号和槽函数添加的信息
QT_MOC_LITERAL(2, 19, 0), // ""
QT_MOC_LITERAL(3, 20, 21) // "on_pushButton_clicked"

    },
    "MainWindow\0sigTest\0\0on_pushButton_clicked"//所有的信号和槽函数的名称都添加到元对象的信息 MainWindow作为 const char * QMetaObject ::className () const 所返回的数据
};

struct qt_meta_stringdata_Widget_t {
    QByteArrayData data[9];
    char stringdata0[68];
};
  1. 每个QByteArray对应一个下面\0结尾的字符串,以此方便对字符串数据的管理

在这里插入图片描述

当我们不停的增加信号的时候,就会向这部分的字符串数据中添加新的信号量和槽函数的描述。

生成元对象类的详细信息描述

static const uint qt_meta_data_MainWindow[] = {

 // content:
       7,       // revision
       0,       // classname
       0,    0, // classinfo
       2,   14, // methods 这个元对象所包含的信号和槽函数的方法范围其中包含一个signal和一个slot
       0,    0, // properties
       0,    0, // enums/sets
       0,    0, // constructors
       0,       // flags
       1,       // signalCount

 // signals: name, argc, parameters, tag, flags
       1,    0,   24,    2, 0x06 /* Public */,//第一值是QByteArrayData中的索引值,用来找对应的字符串名称,第二个是参数个数,第三个是参数大小

 // slots: name, argc, parameters, tag, flags
       3,    0,   25,    2, 0x08 /* Private */,//这里出现的1,3这些序号在提交信号处理的过程中查找槽函数时是会用到的

 // signals: parameters
    QMetaType::Void,

 // slots: parameters
    QMetaType::Void,

       0        // eod
};

初始化静态的元对象

QT_INIT_METAOBJECT const QMetaObject MainWindow::staticMetaObject = {
    { &QMainWindow::staticMetaObject, qt_meta_stringdata_MainWindow.data,
      qt_meta_data_MainWindow,  qt_static_metacall, nullptr, nullptr}
};

重写const QMetaObject *QObject::metaObject() const方法

const QMetaObject *MainWindow::metaObject() const //返回上述初始化了的静态元对象的指针
{
    return QObject::d_ptr->metaObject ? QObject::d_ptr->dynamicMetaObject() : &staticMetaObject;
}

允许指定的元对象类型名称转换成对应的QObject对象指针

void *MainWindow::qt_metacast(const char *_clname)
{
    if (!_clname) return nullptr;
    if (!strcmp(_clname, qt_meta_stringdata_MainWindow.stringdata0))
        return static_cast<void*>(this);//如果与字符串数据中的第一个数据名称一致,则返回Mainwindow的对象指针
    return QMainWindow::qt_metacast(_clname);
}

重写 int QOject::qt_metacall(QMetaObject::Call _c, int _id, void **_a)函数

当信号被触发的时候,走到元对象系统的静态方法int QMetaObject::metacall(QObject *object, Call cl, int idx, void **argv)时,会调用Object的qt_metacall方法,而这个方法时个纯虚函数,moc编译器会帮我们生成mainwindow类的metacall的函数实现

int MainWindow::qt_metacall(QMetaObject::Call _c, int _id, void **_a)
{
    _id = QMainWindow::qt_metacall(_c, _id, _a);
    if (_id < 0)
        return _id;
    if (_c == QMetaObject::InvokeMetaMethod) {
        if (_id < 2)
            qt_static_metacall(this, _c, _id, _a);
        _id -= 2;
    } else if (_c == QMetaObject::RegisterMethodArgumentMetaType) {
        if (_id < 2)
            *reinterpret_cast<int*>(_a[0]) = -1;
        _id -= 2;
    }
    return _id;
}

qt_static_metacall的具体实现也由moc编译器自动生成

void MainWindow::qt_static_metacall(QObject *_o, QMetaObject::Call _c, int _id, void **_a)
{
    if (_c == QMetaObject::InvokeMetaMethod) {
        MainWindow *_t = static_cast<MainWindow *>(_o);
        Q_UNUSED(_t)
        switch (_id) {
        case 0: _t->sigTest(); break;
        case 1: _t->on_pushButton_clicked(); break;
        default: ;
        }
    } else if (_c == QMetaObject::IndexOfMethod) {
        int *result = reinterpret_cast<int *>(_a[0]);
        {
            typedef void (MainWindow::*_t)();
            if (*reinterpret_cast<_t *>(_a[1]) == static_cast<_t>(&MainWindow::sigTest)) {
                *result = 0;
                return;
            }
        }
    }
    Q_UNUSED(_a);
}

为所有的信号添加函数实现

实现体的内容都是调用元对象的active方法,并传递参数。如果还有其他的信号,则再增加一个函数定义

// SIGNAL 1
void MainWindow::sigTestEx()
{
    QMetaObject::activate(this, &staticMetaObject, 1, nullptr);//静态方法
}

Connect函数让QMetaObject可以管理调度Object的信号槽

QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type)
会为每个sender对象添加一个QObjectConnectionListVector类型的列表connectionLists来记录连接到这个sendor上的所有的信号(signalindex)对应的接受者以及他们的槽函数的信息(slotindex)
当QMetaObject的active被触发的时候,会遍历sender对象的connectionLists 。通过几种不同的途径调用到QObject子类的槽函数中

执行receiver的元对象的static_metacall函数指针

struct { // private data
        const QMetaObject *superdata;
        const QByteArrayData *stringdata;
        const uint *data;
        typedef void (*StaticMetacallFunction)(QObject *, QMetaObject::Call, int, void **);
        StaticMetacallFunction static_metacall;
        const QMetaObject * const *relatedMetaObjects;
        void *extradata; //reserved for future use
    } d;

在moc生产的元对象代码中,我们初始化静态元对象数据时指定了第四个成员变量为qt_static_metacall

通过QMetaObject::metacall 调用某个对象的int qt_metacall(QMetaObject::Call _c, int _id, void **_a)

而这个方法在上述moc过程中被重写了,使其可以调用到qt_static_metacall

总结

可见元对象编译器主要做两件事
为对象生成数据信息(类名称,信号和槽名称,参数类型关联)
给信号函数和槽函数生成调用实现的代码,再将代码交由QMetaObject进行管理调度,所有信号和槽函数的关联在对象内部是不可见的。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Qt是一款流行的跨平台C++框架,有着强大的功能和丰富的类库。Qt的核心机制包括Qt对象系统信号机制。 Qt对象系统Qt的一个重要特性,它是Qt实现反射的基础。在C++中,反射能够在运行时获取类的信息,如类名、属性、方法等,并在运行时动态地创建、调用对象Qt对象系统通过为每个QObject派生的子类生成一个对象,实现了C++的反射机制。对象系统使得Qt能够在运行时获取QObject派生类的信息,并提供了一系列函数来操作这些对象Qt信号机制是Qt的核心机制之一,它用于实现对象之间的通信。信号机制基于发布-订阅模式,其中一个对象发送信号,而另一个对象通过连接到这个信号函数来接收信号并进行相应的处理。信号机制具有松耦合的特性,可以实现对象之间的解耦。 在信号机制中,信号是由QObject派生类定义的特殊函数,用于声明某个特定事件发生时要发送的信号函数是QObject派生类中的普通函数,用于接收这个信号,并且执行相应的处理逻辑。信号通过信号连接函数进行连接,这样当信号触发时,与之连接的函数就会被自动调用。 Qt对象系统信号机制是Qt强大功能的基石。对象系统实现了C++的反射机制,允许在运行时获取和操作对象的信息。信号机制使对象之间的通信变得简单和易用,提供了一种灵活而高效的方式来实现对象间的解耦。通过这些核心机制,Qt能够帮助开发人员更快速、更简便地开发高质量的跨平台应用程序。 ### 回答2: qt核心机制是指Qt框架的底层机制,主要包括Qt对象系统Qt信号原理。 Qt对象系统Qt框架中的一个重要概念,它在C++语言的基础上添加了一套对象(Meta Object)系统对象系统编译过程中生成了额外的代码,使得我们可以在运行时获得更多的对象信息。通过对象系统Qt实现了信号机制、宏(MOC)编译和反射等功能。对象系统实际上是一种面向对象的编程方式,通过它可以实现Qt特有的功能,如动态属性、动态信号等。 Qt信号原理是Qt框架中的一个重要特性,用于对象间的通信。信号是一种异步通信方式,通过信号发送者(Sender)发送信号,接收者(Receiver)通过函数(Slot)响应信号信号是通过对象系统实现的,编译器会在MOC编译阶段解析信号的声明,并在运行时建立连接关系。这种机制使得Qt程序的耦合性更低,灵活性更高,同时也为多线程编程提供了一种方便的方式。 总的来说,Qt核心机制包括了Qt对象系统信号原理。对象系统Qt框架提供了反射、动态属性和动态信号等功能,信号机制实现了对象间的异步通信。这些机制使得Qt框架具有高度的可扩展性、灵活性和跨平台性,为开发者提供了一种便捷、高效的方式来构建应用程序。 ### 回答3: Qt是一种跨平台的应用程序框架,具有丰富的功能和强大的性能。Qt核心机制是指Qt框架的基础机制,包括Qt对象系统Qt信号原理。 Qt对象系统Qt框架的核心组成之一,用于实现Qt的一些特殊功能,如信号机制和动态属性。Qt对象系统通过将所有的类对象都派生自QObject基类,实现了一种反射机制,使得对象之间可以动态地连接和交互。通过使用对象系统Qt可以实现面向对象编程的高级特性,如对象间的信号的连接,对象的属性系统以及对象的内省(即动态获取对象的属性和方法信息)等。 Qt信号原理是Qt框架实现事件驱动的关键机制。信号机制允许不同对象之间进行松散的耦合,通过信号的方式进行通信。信号是一种特殊的成员函数,用于表示某个事件的发生,是一种普通的成员函数,用于响应信号的发出。当一个信号被发出时,Qt框架会自动将信号进行匹配,并调用对应的函数。这种机制使得对象之间的通信更加灵活和高效,可以实现事件的传递和处理,避免了显式的函数调用和回调函数的使用。 综上所述,Qt的核心机制包括Qt对象系统Qt信号原理。通过对象系统Qt实现了一种反射机制,使得对象之间可以动态地连接和交互;通过信号机制,Qt实现了一种松散耦合的事件处理方式,提高了对象之间的通信效率和灵活性。这些机制是Qt框架的重要组成部分,为开发者提供了更加强大和易用的工具和功能。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值