Qt中自定义结构体及其序列化

自定义结构体

在实际应用程序开发中,我们经常需要处理复杂的数据模型并对其进行内部和外部操作。在这些情况下,需要一种能够组织、描述和管理数据模型的机制,并且要支持灵活的数据操作和定制化需求。自定义结构体正好满足了这些要求。

自定义结构体为提高代码的清晰度,减少代码的重复和冗余,简化数据处理和传递提供了便利,使得程序开发更加高效和顺畅。另外,自定义结构体也能够帮助我们更好地组织数据和面向对象编程思想以支持代码复用和分离关注点,进而提高代码的质量和可维护性。

具体来讲,使用自定义结构体有以下好处:

  1. 数据类型的封装:自定义结构体允许将多个基本数据类型组合在一起,形成更加复杂和有意义的数据类型,如人员信息、学生课程表等等,而不仅仅是简单地让基本数据类型单独存在。这样可以减少变量数量,提高代码可读性和易用性。
  2. 简化数据传递:通过自定义结构体,我们可以将多个数据属性组装到一个对象中,并以此来传输或存储相互关联的多个数据记录或元素。这一方便了数据传递和交互,也简洁清晰代码,尤其在函数参数传递,我们可以只传递一个结构体对象而非多个具体参数。
  3. 代码复用:由于结构体对象具有清晰的语义和内部关系,因此我们可以在开发过程中轻松重用代码,并对其进行修改和扩展,避免了代码的冗余性和复杂性。
  4. 应对需求变化:利用自定义结构体,我们可以为不同的需求场景定制不同的数据结构以适应不断变化的业务需求。例如,某些对象属性可能只在特定情况下才需要使用,我们就可以在结构体中动态调整并优化数据以支持不同的需求场景,保证程序代码有良好的可维护性和扩展性。

序列化

在实际应用程序开发中,我们经常需要将结构化数据保存到文件、网络传输或数据库中,并且这些数据可能会被多个系统或平台使用。在这些情况下,将数据进行序列化可以使得数据以更加通用和标准化的方式进行存储和传输,从而提高了数据的可读性和可维护性。将自定义结构体进行序列化可使数据更易于管理、存储和共享,并提高了跨平台和应用程序的数据交互性,为分布式环境下基于数据的协同工作奠定了基础。

具体来讲,将数据或自定义的结构体序列化有以下好处:

  1. 数据持久化:序列化使得我们能够将内存中的数据保存到文件或数据库中,从而使数据能够长期存储并在需要时进行访问和操作,支持数据的永久保存。这对于需要保存大量的数据和历史数据记录的应用程序非常重要。
  2. 数据传输:序列化能够将结构化数据格式化为不同的传输协议,如JSON、XML、二进制流等等,进而可以通过网络进行数据传输,支持数据在分布式环境中的交互和共享。这对于云计算、物联网等需要跨越多个服务器进行数据交互的场景中非常关键。
  3. 数据解释:序列化形成了公共格式的处理数据方法,参与方配合共同认知处理数据,可以有效地降低沟通成本和避免解释的不确定性。
  4. 跨编程语言兼容性:序列化使得数据以更加通用和标准化的方式进行存储和传输,不依赖于特定编程语言或框架实现,因此能够支持跨多个平台和应用程序的数据交互与互操作。例如同样的JSON格式可以在JAVA、C++等大部分编程语言中解析到对象。

基于QJson序列化

在 QT 中,可以使用 QJsonDocument 类将自定义结构体转换为 JSON 字符串。

QJsonDocument 是 QT 模块中专门用于处理 JSON 数据的类,它提供了一些方法来读取、创建、编码和解析 JSON 数据。

为了将自定义结构体转换为 JSON 字符串,需要先将结构体中的每个成员转换为 QJsonObject,然后使用 QJsonDocument::toJson() 方法将其转换为 JSON 字符串。

转换成JSON字符串后,可通过调试信息进行打印,或者将数据持久化到json文件中。

代码示例如下:

#include <QCoreApplication>
#include <QJsonDocument>
#include <QJsonObject>
#include <QDebug>
#include <QFile>

// 自定义结构体
struct Person {
    QString name;
    int age;
    float salary;

    // 转换为 QJsonObject 对象
    QJsonObject toJsonObject() const {
        QJsonObject obj;
        obj["name"] = name;
        obj["age"] = age;
        obj["salary"] = static_cast<double>(salary);
        return obj;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 初始化自定义结构体
    Person person = {"John", 30, 5000.50};

    // 将结构体转换为 JSON 字符串
    QJsonObject jsonObj = person.toJsonObject();
    QJsonDocument jsonDoc(jsonObj);
    QByteArray jsonString = jsonDoc.toJson(QJsonDocument::Compact);

    qDebug() << "JSON string: " << jsonString;

    // 将 JSON 对象转换为文本流
    QByteArray jsonToFile = jsonDoc.toJson(QJsonDocument::Indented);

    // 创建输出文件,并将 JSON 写入文件
    QFile file("output.json");
    if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
        QTextStream stream(&file);
        stream << jsonToFile;
        file.close();
    }

    return a.exec();
}

运行后,可在调试窗口和json文件中查看相应的输出。

通过qDebug()输出结构体

在 QT 中,可以使用 QDebug 和 qInfo 工具类更方便地输出自定义结构体的内容。QDebug 提供了一个强大的调试输出流,用于输出各种类型的数据,而 qInfo 则是一种简化的输出格式,专门用于输出应用程序信息。

为了使用这些方法,我们需要在自定义结构体中实现一个友元函数 operator<<(),该函数将自定义结构体的内容传递给 QDebug 或 qInfo 流对象进行输出。

代码示例如下:

#include <QCoreApplication>
#include <QDebug>
#include <QLoggingCategory>


// 声明日志分类
Q_DECLARE_LOGGING_CATEGORY(myapp)

// 自定义结构体
struct Person {
    QString name;
    int age;
    float salary;

    // 输出到 qDebug 流
    friend QDebug operator<<(QDebug dbg, const Person &p) {
        QDebugStateSaver saver(dbg);
        dbg.nospace() << "Person(" << p.name << ", " << p.age << ", " << p.salary << ")";
        return dbg;
    }

    // 输出到 qInfo 流
    friend void operator<<(QLoggingCategory &logger, const Person &p) {
        qInfo(myapp) << "Person(" << p.name << ", " << p.age << ", " << p.salary << ")";
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 初始化自定义结构体
    Person person = {"John", 30, 5000.50};

    // 输出自定义结构体
    qDebug() << person;
    qInfo() << person;

    return a.exec();
}

在上述示例程序中,我们重载了两个运算符,分别将自定义结构体传递给 qDebug 流和 qInfo 流对象进行输出。在输出到 qDebug 流时,我们使用了 QDebugStateSaver 对象来保存 QDebug 流的状态,确保输出不会被打断或中断;在输出到 qInfo 流时,我们使用了 Q_DECLARE_LOGGING_CATEGORY 宏定义声明了一个日志类别 myapp 并设置级别为 info。

总之,在 QT 中,QDebug 和 qInfo 工具类提供了一种便捷的方法,可以快速地输出自定义结构体的内容以及其他调试信息。通过重载运算符,并将结构体数据传递给流对象,我们可以灵活、自由地定制输出内容和格式,从而更好地满足开发需求。

通过glog输出结构体

glog是Google开发的一款C++日志库,它提供了高效的、灵活的和易于使用的日志记录工具。在使用glog输出自定义结构体时,能够直接将结构体对象以日志形式记录下来,从而方便快捷地进行程序调试、错误排查和性能优化。输出自定义结构体的意义主要有以下几个方面:

  1. 可读性更佳:通过将自定义结构体以标准的格式输出到日志中,在出现问题或故障时,可以更加快速有效地找到问题所在,因为我们不需要逐个查看每个字段和值。
  2. 提高代码效率:当需要输出大量数据结构信息来帮助我们理解和调试代码是,输出日志比手动把信息打印到控制台要更加简洁明了,并且可以避免过多打印影响控制台可读性。
  3. 代码重用:在多个函数或文件中输出相似的日志格式,尤其是对于类似的结构体对象数据,使用glog就可以在程序中复用日志输出代码,大幅提高了代码的复用性,降低了代码维护成本。
  4. 部署监控:在运行时输出部分自定义结构体属性的实时状态指标,方便其他系统或者第三方平台进行数据处理和监控。

使用 glog 打印自定义结构体的数据,我们可以通过重载运算符<<来实现。glog 提供了 VLOG、LOG 和 DLOG 等宏命令来输出调试信息,分别对应 INFO、ERROR 和 DEBUG 级别的信息输出。

下面是一个示例:

#include <QCoreApplication>
#include <iostream>
#include <string>
#include "glog/logging.h"


// 自定义结构体
struct Person {
    std::string name;
    int age;
    double salary;

    // 重载 << 运算符
    friend std::ostream& operator<<(std::ostream& os, const Person& p) {
        os << "Person(" << p.name << ", " << p.age << ", " << p.salary << ")";
        return os;
    }
};

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    // 初始化 glog 库
    google::InitGoogleLogging(argv[0]);

    // 设置日志级别及输出格式
    google::SetStderrLogging(google::GLOG_INFO);

    // 初始化自定义结构体对象
    Person person = {"John", 30, 5000.50};

    // 输出自定义结构体到 LOG(INFO)
    LOG(INFO) << person;

    return a.exec();
}

控制台和文件中的输出结果:

I20230520 10:44:27.077448 17126 main.cpp:34] Person(John, 30, 5000.5)

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zw_ggr_2017

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值