在 Qt 中,信号(Signal)和槽(Slot)机制默认支持许多内置类 型(如 int、QString、QList 等),但如果要传输 自定义数据结构(如结构体、类对象),需要额外处理。以下是几种实现方式:

1. 使用 QVariant 包装自定义类型(推荐)
QVariant 是 Qt 的通用数据容器,可以存储任意类型。要让 QVariant 支持自定义类型,需要:

注册自定义类型(Q_DECLARE_METATYPE + qRegisterMetaType)。

在信号/槽中使用 QVariant 作为参数类型。

示例:传输自定义结构体
#include <QObject>
#include <QVariant>
 
// 1. 定义自定义数据结构
struct Person {
    QString name;
    int age;
};
 
// 2. 声明元类型支持(必须在头文件或全局作用域)
Q_DECLARE_METATYPE(Person)
 
class DataSender : public QObject {
    Q_OBJECT
public:
    void sendData() {
        Person p {"Alice", 25};
        emit dataSent(QVariant::fromValue(p)); // 转换为 QVariant
    }
 
signals:
    void dataSent(QVariant personData); // 信号参数用 QVariant
};
 
class DataReceiver : public QObject {
    Q_OBJECT
public slots:
    void onDataReceived(QVariant data) {
        Person p = data.value<Person>(); // 从 QVariant 提取
        qDebug() << "Received:" << p.name << p.age;
    }
};
 
int main() {
    // 3. 注册元类型(必须在连接信号槽前调用)
    qRegisterMetaType<Person>("Person");
 
    DataSender sender;
    DataReceiver receiver;
    QObject::connect(&sender, &DataSender::dataSent, 
                     &receiver, &DataReceiver::onDataReceived);
 
    sender.sendData();
    return 0;
}
 

关键点
Q_DECLARE_METATYPE:让 QVariant 能识别自定义类型。

qRegisterMetaType:让信号槽系统能处理该类型(跨线程时必须调用)。

QVariant::fromValue() / value<T>():类型与 QVariant 互转。

2. 使用 Q_GADGET 宏(Qt 5+)
如果自定义类型是 轻量级结构体(无继承自 QObject),可以用 Q_GADGET 宏 使其支持属性访问和信号槽(类似 Q_OBJECT 的简化版)。

示例
#include <QObject>
 
// 1. 使用 Q_GADGET 声明
struct Person {
    Q_GADGET  // 提供元对象能力,但不支持信号槽
    Q_PROPERTY(QString name MEMBER name)
    Q_PROPERTY(int age MEMBER age)
 
public:
    QString name;
    int age;
};
 
// 2. 仍然需要注册元类型
Q_DECLARE_METATYPE(Person)
 
// 信号槽用法与 QVariant 方式相同
 

适用场景
需要让结构体支持 属性反射(如 QML 访问)。

比 QObject 更轻量,但功能有限(不能直接定义信号槽)。

3. 继承 QObject 并作为指针传递
如果自定义类型继承自 QObject,可以直接以指针形式传递(需注意对象生命周期管理)。

示例
#include <QObject>
 
class Person : public QObject {
    Q_OBJECT
public:
    Person(QString name, int age) : name(name), age(age) {}
    QString name;
    int age;
};
 
class Sender : public QObject {
    Q_OBJECT
public:
    void send() {
        auto person = new Person("Bob", 30);
        emit sendPerson(person); // 传递指针
    }
signals:
    void sendPerson(Person* person);
};
 
class Receiver : public QObject {
    Q_OBJECT
public slots:
    void receivePerson(Person* person) {
        qDebug() << "Received:" << person->name;
        person->deleteLater(); // 确保内存释放
    }
};

注意事项
所有权管理:接收方需负责删除对象(如 deleteLater),避免内存泄漏。

适用于复杂对象,但需谨慎处理生命周期。

4. 使用共享指针(QSharedPointer 或 std::shared_ptr)
如果自定义数据结构较大或需要共享所有权,可以使用智能指针。

示例
#include <QSharedPointer>
 
struct Person {
    QString name;
    int age;
};
 
class Sender : public QObject {
    Q_OBJECT
public:
    void send() {
        auto person = QSharedPointer<Person>::create("Charlie", 40);
        emit sendPerson(person);
    }
signals:
    void sendPerson(QSharedPointer<Person> person);
};
 
class Receiver : public QObject {
    Q_OBJECT
public slots:
    void receivePerson(QSharedPointer<Person> person) {
        qDebug() << "Received:" << person->name;
    }
};
 

优点
自动管理内存,避免悬垂指针。

适合跨线程传递数据。

5. 序列化为 QByteArray(通用但低效)
将自定义类型序列化为字节流(如 JSON、二进制),通过 QByteArray 传输。

示例(JSON 序列化)
#include <QJsonDocument>
#include <QJsonObject>
 
struct Person {
    QString name;
    int age;
    QByteArray toJson() const {
        QJsonObject obj;
        obj["name"] = name;
        obj["age"] = age;
        return QJsonDocument(obj).toJson();
    }
    static Person fromJson(QByteArray json) {
        auto obj = QJsonDocument::fromJson(json).object();
        return {obj["name"].toString(), obj["age"].toInt()};
    }
};
 
// 信号槽参数使用 QByteArray
 

适用场景
需要跨进程或网络传输。

数据较大时效率较低。

总结

推荐选择
1.优先用 QVariant + qRegisterMetaType(平衡易用性与功能)。

2.如果类型简单且需 QML 访问,用 Q_GADGET。

3.如果对象生命周期复杂,用智能指针或 QObject 指针。
————————————————

原文链接:https://blog.csdn.net/weixin_43050542/article/details/149807806

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐