QT实战:Qt6 编码规范模板

QT实战:Qt6 编码规范模板

Qt6 编码规范模板

以下模板包括信号槽参数/返回值编码、字符串参数传递、Lambda 表达式编码、跨线程信号槽编码等核心场景,完全适配 QT_NO_CAST_FROM_ASCII/QT_NO_CAST_TO_ASCII 启用环境。

一、工程配置模板
1. CMakeLists.txt 编码配置
CMake 复制代码
# Qt6 编码安全配置(核心)
target_compile_definitions(${PROJECT_NAME} PRIVATE
    # 禁用 ASCII 隐式转换,强制显式编码处理
    QT_NO_CAST_FROM_ASCII
    QT_NO_CAST_TO_ASCII
    # 禁用 QString 转 char* 的隐式转换(可选,增强安全性)
    QT_NO_CAST_FROM_BYTEARRAY
    # 统一编码为 UTF-8(Windows 平台必加)
    _UNICODE
    UNICODE
)

# C++ 标准(Qt6 推荐 C++17 及以上)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# Windows 平台编码编译选项(避免中文乱码)
if(WIN32)
    target_compile_options(${PROJECT_NAME} PRIVATE /utf-8)
endif()
2. .pro 文件编码配置
Prolog 复制代码
# Qt6 编码安全配置(核心)
DEFINES += \
    QT_NO_CAST_FROM_ASCII \
    QT_NO_CAST_TO_ASCII \
    QT_NO_CAST_FROM_BYTEARRAY

# 统一 C++ 标准
CONFIG += c++17

# 编码编译选项(跨平台)
win32 {
    QMAKE_CXXFLAGS += /utf-8
    QMAKE_CFLAGS += /utf-8
}
unix:!macx {
    QMAKE_CXXFLAGS += -finput-charset=utf-8 -fexec-charset=utf-8
}
macx {
    QMAKE_CXXFLAGS += -std=c++17 -finput-charset=utf-8
}

# 禁用 QString 隐式转换为 ASCII(可选)
DEFINES += QT_STRICT_ITERATORS
二、通用编码规范头文件(encoding_standard.h)
C++ 复制代码
#ifndef ENCODING_STANDARD_H
#define ENCODING_STANDARD_H

#include <QString>
#include <QLatin1String>
#include <QLatin1Char>
#include <QByteArray>
#include <string>
#include <functional>

/**
 * @brief Qt6 编码规范工具类
 * 适配 QT_NO_CAST_FROM_ASCII/QT_NO_CAST_TO_ASCII 启用场景
 * 信号槽专属编码处理
 */
class EncodingStandard
{
public:
    // 禁用构造函数(纯工具类)
    EncodingStandard() = delete;
    ~EncodingStandard() = delete;

    // ========== 基础编码转换==========
    /**
     * @brief std::string 转 QString(UTF-8 编码,通用场景)
     * @param str 输入的 std::string(UTF-8 编码)
     * @return 转换后的 QString
     */
    static QString stdStringToQString(const std::string& str)
    {
        return QString::fromUtf8(str.c_str(), static_cast<int>(str.size()));
    }

    /**
     * @brief std::string 转 QString(本地编码,适配系统特定场景)
     * @param str 输入的 std::string(本地编码)
     * @return 转换后的 QString
     */
    static QString stdStringToQStringLocal(const std::string& str)
    {
        return QString::fromLocal8Bit(str.c_str(), static_cast<int>(str.size()));
    }

    /**
     * @brief QString 转 std::string(UTF-8 编码,通用场景)
     * @param qstr 输入的 QString
     * @return 转换后的 std::string(UTF-8 编码)
     */
    static std::string qStringToStdString(const QString& qstr)
    {
        QByteArray utf8Bytes = qstr.toUtf8();
        return std::string(utf8Bytes.constData(), utf8Bytes.size());
    }

    /**
     * @brief QString 转 std::string(本地编码,适配系统特定场景)
     * @param qstr 输入的 QString
     * @return 转换后的 std::string(本地编码)
     */
    static std::string qStringToStdStringLocal(const QString& qstr)
    {
        QByteArray localBytes = qstr.toLocal8Bit();
        return std::string(localBytes.constData(), localBytes.size());
    }

    /**
     * @brief 路径拼接(安全处理结尾分隔符)
     * @param parentPath 父路径
     * @param childPath 子路径/文件名
     * @return 拼接后的完整路径
     */
    static QString joinPath(const QString& parentPath, const QString& childPath)
    {
        if (parentPath.isEmpty()) {
            return childPath;
        }
        // 安全处理路径分隔符(跨平台兼容)
        QString result = parentPath;
        if (!result.endsWith(QLatin1Char('/')) && !result.endsWith(QLatin1Char('\\'))) {
            result += QLatin1Char('/');
        }
        return result + childPath;
    }

    /**
     * @brief 空字符串常量(替代 "",避免隐式转换)
     */
    static const QString& emptyString()
    {
        static const QString empty = QString();
        return empty;
    }

    // ==========信号槽专属编码处理 ==========
    /**
     * @brief 信号槽参数转换:char* 数组转 QStringList(UTF-8 编码)
     * 场景:命令行参数、外部接口传参等
     * @param argc 参数个数
     * @param argv char* 数组
     * @return 编码安全的 QStringList
     */
    static QStringList argvToQStringList(int argc, char* argv[])
    {
        QStringList result;
        for (int i = 0; i < argc; ++i) {
            result.append(QString::fromUtf8(argv[i]));
        }
        return result;
    }

    /**
     * @brief 信号槽 Lambda 表达式字符串参数封装
     * 场景:避免在 Lambda 中直接使用 const char* 字面量
     * @param func 接收 QString 参数的 Lambda 函数
     * @param str const char* 字符串(UTF-8 编码)
     */
    template<typename Func>
    static void invokeLambdaWithString(Func&& func, const char* str)
    {
        func(QString::fromUtf8(str));
    }

    /**
     * @brief 跨线程信号槽字符串参数安全传递(避免编码丢失)
     * @param qstr 待传递的 QString
     * @return 可安全跨线程的 QByteArray(UTF-8 编码)
     */
    static QByteArray stringForCrossThread(const QString& qstr)
    {
        return qstr.toUtf8();
    }

    /**
     * @brief 跨线程接收字符串参数(还原编码)
     * @param bytes 跨线程传递的 QByteArray
     * @return 还原后的 QString
     */
    static QString stringFromCrossThread(const QByteArray& bytes)
    {
        return QString::fromUtf8(bytes);
    }
};

// ========== 常用宏定义(简化编码)==========
/**
 * @brief 字符串字面量(编译期优化,优先使用)
 */
#define STR_LITERAL(str) QStringLiteral(str)

/**
 * @brief 单字符字面量(替代 QChar(char))
 */
#define CHAR_LITERAL(ch) QLatin1Char(ch)

/**
 * @brief 临时字符串比较(不分配内存,仅用于比较/查找)
 */
#define LATIN1_STR(str) QLatin1String(str)

/**
 * @brief 信号槽空字符串参数(替代 "",避免隐式转换)
 */
#define SIGNAL_SLOT_EMPTY_STR EncodingStandard::emptyString()

/**
 * @brief 跨线程字符串参数封装(简化调用)
 */
#define CROSS_THREAD_STR(str) EncodingStandard::stringForCrossThread(str)

/**
 * @brief 跨线程字符串参数还原(简化调用)
 */
#define FROM_CROSS_THREAD_STR(bytes) EncodingStandard::stringFromCrossThread(bytes)

#endif // ENCODING_STANDARD_H
三、信号槽编码规范使用示例(完整 demo)
C++ 复制代码
#include "encoding_standard.h"
#include <QCoreApplication>
#include <QObject>
#include <QThread>
#include <QDebug>

// 自定义信号槽类
class SignalSlotDemo : public QObject
{
    Q_OBJECT
public:
    explicit SignalSlotDemo(QObject *parent = nullptr) : QObject(parent) {}

signals:
    // ========== 信号定义规范 ==========
    // 1. 字符串参数必须用 QString,禁用 const char*
    void sendMessage(const QString& msg);
    // 2. 跨线程信号优先用 QByteArray(UTF-8)传递字符串,避免编码丢失
    void sendCrossThreadData(const QByteArray& data);
    // 3. 空参数默认值必须用 SIGNAL_SLOT_EMPTY_STR,禁用 ""
    void sendConfig(const QString& path = SIGNAL_SLOT_EMPTY_STR);

public slots:
    // ========== 槽函数编码规范 ==========
    void onMessageReceived(const QString& msg)
    {
        // 调试输出必须用 STR_LITERAL 显式构造
        qDebug() << STR_LITERAL("收到消息:") << msg;

        // 字符串处理:禁用 const char* 隐式转换
        if (msg.startsWith(LATIN1_STR("error"))) { // 比较用 LATIN1_STR,高效
            qDebug() << STR_LITERAL("检测到错误消息:") << msg;
        }
    }

    void onCrossThreadDataReceived(const QByteArray& data)
    {
        // 跨线程参数还原编码
        QString str = FROM_CROSS_THREAD_STR(data);
        qDebug() << STR_LITERAL("跨线程收到数据:") << str;
    }

    void onConfigReceived(const QString& path)
    {
        // 空参数判断:用 isEmpty(),禁用 == ""
        if (path.isEmpty()) {
            qDebug() << STR_LITERAL("配置路径为空,使用默认路径");
            return;
        }

        // 路径拼接:用工具类安全处理
        QString fullPath = EncodingStandard::joinPath(path, STR_LITERAL("app.conf"));
        qDebug() << STR_LITERAL("配置路径:") << fullPath;
    }
};

// 子线程工作类
class Worker : public QObject
{
    Q_OBJECT
public slots:
    void doWork()
    {
        // 子线程发送跨线程信号
        QString msg = STR_LITERAL("子线程处理完成");
        emit sendCrossThreadMsg(CROSS_THREAD_STR(msg));
    }

signals:
    void sendCrossThreadMsg(const QByteArray& data);
};

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

    // ========== 1. 命令行参数编码转换 ==========
    QStringList args = EncodingStandard::argvToQStringList(argc, argv);
    qDebug() << STR_LITERAL("命令行参数:") << args;

    // ========== 2. 普通信号槽连接 ==========
    SignalSlotDemo demo;
    // 连接信号槽:Lambda 表达式中禁用 const char* 字面量
    QObject::connect(&demo, &SignalSlotDemo::sendMessage,
                     &demo, &SignalSlotDemo::onMessageReceived);

    // 发送信号:字符串参数必须用 STR_LITERAL 构造
    emit demo.sendMessage(STR_LITERAL("测试消息 123"));
    // 发送空参数信号:用 SIGNAL_SLOT_EMPTY_STR
    emit demo.sendConfig(SIGNAL_SLOT_EMPTY_STR);
    // 发送带路径信号:显式构造 QString
    emit demo.sendConfig(STR_LITERAL("/data/config"));

    // ========== 3. 跨线程信号槽编码 ==========
    QThread workerThread;
    Worker worker;
    worker.moveToThread(&workerThread);

    // 跨线程信号槽连接
    QObject::connect(&worker, &Worker::sendCrossThreadMsg,
                     &demo, &SignalSlotDemo::onCrossThreadDataReceived);
    QObject::connect(&workerThread, &QThread::started,
                     &worker, &Worker::doWork);

    // 启动子线程
    workerThread.start();

    // ========== 4. Lambda 表达式信号槽编码 ==========
    QObject::connect(&workerThread, &QThread::finished,
                     []() {
                         // Lambda 中字符串必须用 STR_LITERAL
                         qDebug() << STR_LITERAL("子线程已结束");
                     });

    return a.exec();
}

#include "main.moc"
四、Qt6 信号槽编码规范检查清单
检查项 规范要求 错误示例 正确示例
信号参数 字符串参数必须用 QString,禁用 const char* void sendMsg(const char* msg); void sendMsg(const QString& msg);
信号默认值 空字符串默认值用 SIGNAL_SLOT_EMPTY_STR void sendMsg(const QString& msg = ""); void sendMsg(const QString& msg = SIGNAL_SLOT_EMPTY_STR);
跨线程信号 字符串参数优先用 QByteArray(UTF-8) void sendCrossThread(const QString& str); void sendCrossThread(const QByteArray& data);
槽函数参数 禁用 const char*,统一用 QString/QByteArray void onMsg(const char* msg); void onMsg(const QString& msg);
Lambda 表达式 内部字符串必须用 STR_LITERAL [](){ qDebug() << "test"; } [](){ qDebug() << STR_LITERAL("test"); }
命令行参数 必须转为 QStringList,禁用 char* 直接使用 QString arg = argv[1]; QStringList args = argvToQStringList(argc, argv);
字符串比较 优先用 LATIN1_STR,避免内存分配 if (msg == "error") if (msg.startsWith(LATIN1_STR("error")))
跨线程参数还原 必须用 FROM_CROSS_THREAD_STR 还原编码 QString str = QString(data); QString str = FROM_CROSS_THREAD_STR(data);

总结

新增核心要点(信号槽专属)
  1. 信号参数规范 :字符串参数必须用 QString,禁用 const char*;空默认值用 SIGNAL_SLOT_EMPTY_STR,禁用 ""

  2. 跨线程编码安全 :跨线程信号优先用 QByteArray(UTF-8)传递字符串,通过 CROSS_THREAD_STR/FROM_CROSS_THREAD_STR 封装/还原;

  3. Lambda 表达式 :内部所有字符串字面量必须用 STR_LITERAL 显式构造,禁用 const char*

  4. 命令行参数 :通过 argvToQStringList 统一转为 QStringList,避免直接使用 char*

  5. 字符串比较 :槽函数中字符串比较优先用 LATIN1_STR,减少内存分配,提升效率。

该模板完全适配 Qt6 信号槽机制,同时兼容 QT_NO_CAST_FROM_ASCII/QT_NO_CAST_TO_ASCII 启用后的编码规范,可直接复制到项目中落地使用。

相关推荐
用户805533698033 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner3 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz8 天前
QML Hello World 入门示例
qt
xcyxiner11 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner12 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner12 天前
DicomViewer (添加模型类)3
qt
xcyxiner13 天前
DicomViewer (目录调整) 2
qt
xcyxiner13 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00615 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术15 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript