Qt 的 元對象系統(Meta-Object System) 是 Qt 核心機制之一,正是它讓 C++ 語言具備了類似腳本語言(如 Python)的反射、動態綁定、屬性系統等能力。
自定義信號與槽,是 Qt 元對象系統最常見、最實用的體現。
🧠 一、什么是元對象系統?
Qt 使用了一個特殊的編譯工具 —— MOC(Meta-Object Compiler),用于解析 Qt 自己擴展的語法(如 signals
, slots
, Q_PROPERTY
, Q_OBJECT
)。
元對象系統的作用:
功能 | 實現 |
---|---|
信號與槽機制 | 通過 MOC 生成信號/槽的元數據與調度代碼 |
運行時類型識別 | 通過 QObject::metaObject() 查詢類名、方法名 |
屬性系統 | Q_PROPERTY , setProperty() , property() |
動態方法調用 | QMetaObject::invokeMethod() |
Qt Designer UI 反射支持 | 識別屬性/信號用于界面綁定 |
📦 二、自定義信號與槽的步驟與語法
要使用自定義信號與槽,你必須從以下基礎開始構建類:
1. 必須繼承 QObject
2. 必須聲明 Q_OBJECT
宏
3. 使用 signals:
和 slots:
關鍵字定義信號和槽
4. 使用 emit
關鍵字發出信號(槽函數無需關鍵字)
🧪 三、完整示例:自定義信號與槽 + 元對象動態調用
我們將構建一個簡單示例:
Notifier
:定義信號Listener
:定義槽main()
:連接信號和槽,并使用QMetaObject
動態調用槽
? Notifier.h
#ifndef NOTIFIER_H
#define NOTIFIER_H#include <QObject>class Notifier : public QObject {Q_OBJECT
public:explicit Notifier(QObject *parent = nullptr);void trigger(int data); // 主動觸發信號signals:void dataReady(int value); // 自定義信號
};#endif // NOTIFIER_H
? Notifier.cpp
#include "Notifier.h"
#include <QDebug>Notifier::Notifier(QObject *parent) : QObject(parent) {}void Notifier::trigger(int data) {qDebug() << "[Notifier] Emitting signal with value:" << data;emit dataReady(data); // 發射信號
}
? Listener.h
#ifndef LISTENER_H
#define LISTENER_H#include <QObject>class Listener : public QObject {Q_OBJECT
public:explicit Listener(QObject *parent = nullptr);public slots:void onDataReceived(int val); // 自定義槽函數
};#endif // LISTENER_H
? Listener.cpp
#include "Listener.h"
#include <QDebug>Listener::Listener(QObject *parent) : QObject(parent) {}void Listener::onDataReceived(int val) {qDebug() << "[Listener] Slot received value:" << val;
}
? main.cpp
#include <QCoreApplication>
#include "Notifier.h"
#include "Listener.h"
#include <QMetaObject>int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);Notifier notifier;Listener listener;// 普通信號與槽連接QObject::connect(¬ifier, &Notifier::dataReady, &listener, &Listener::onDataReceived);// 手動發出信號notifier.trigger(42);// -----------------------// 元對象系統調用槽函數:QMetaObject::invokeMethod(&listener,"onDataReceived",Q_ARG(int, 77)); // 等價于 listener.onDataReceived(77)// -----------------------return a.exec();
}
🔍 四、代碼講解與元對象機制分析
元素 | 說明 |
---|---|
Q_OBJECT | 啟用 MOC,為類生成 metaObject() 、信號注冊表、槽表等元信息 |
signals: | 聲明信號,無需實現,MOC 自動生成代碼 |
slots: | 標記槽函數(普通函數也可連接,但不在元信息中) |
emit | 關鍵詞告訴 MOC 調用其內部生成的 QMetaObject::activate() |
QMetaObject::invokeMethod() | 動態調用函數,適用于運行時控制,例如插件、腳本引擎、UI 綁定等 |
🔧 五、擴展:如何查看元對象信息?
const QMetaObject* metaObj = listener.metaObject();qDebug() << "Class name:" << metaObj->className();
for (int i = 0; i < metaObj->methodCount(); ++i) {QMetaMethod method = metaObj->method(i);qDebug() << "Method:" << method.methodSignature();
}
輸出示例:
Class name: Listener
Method: onDataReceived(int)
🚀 六、高階應用場景
場景 | 描述 |
---|---|
UI 動態綁定 | QML 動態綁定 C++ 信號 |
插件系統 | 插件導出類名和方法名后通過 QMetaObject 動態加載 |
組件通信總線 | 使用信號發射器集中管理事件轉發 |
腳本語言綁定 | Lua、Python 等可通過信號槽機制集成 C++ 動態行為 |
? 七、總結
點 | 說明 |
---|---|
必須使用 Q_OBJECT 宏 | 啟用元對象支持 |
信號無需實現 | MOC 自動生成信號注冊代碼 |
槽函數可使用 slots: 或普通函數 | 推薦使用 public slots: |
信號槽機制基于字符串/元信息 | 可支持動態調用、反射式開發 |
invokeMethod() | 動態執行函數的利器 |