Qt跨平台开发编程技巧总结

一、数据类型

尽量使用Qt提供的数据类型,比如qint32,quint64等。

typedef signed char qint8;         /* 8 bit signed */
typedef unsigned char quint8;      /* 8 bit unsigned */
typedef short qint16;              /* 16 bit signed */
typedef unsigned short quint16;    /* 16 bit unsigned */
typedef int qint32;                /* 32 bit signed */
typedef unsigned int quint32;      /* 32 bit unsigned */
#if defined(Q_OS_WIN) && !defined(Q_CC_GNU)
#  define Q_INT64_C(c) c ## i64    /* signed 64 bit constant */
#  define Q_UINT64_C(c) c ## ui64   /* unsigned 64 bit constant */
typedef __int64 qint64;            /* 64 bit signed */
typedef unsigned __int64 quint64;  /* 64 bit unsigned */

在不同的平台上,基本的C++类型如short,char,int,long,long long会有不同的字长。

最好使用Qt提供的类型qint8,quint8,qint16,quint16,qint32,quint32,qint64,quint64,这些类型能确保字长是不随平台改变的。

二、跨平台适配

当我们在开发一个功能时,由于在win/linux下各自实现方式不同,故我们需要针对平台分别实现。

比如,我们需要编写一个模块获取当前系统的名称。一般来讲,有如下几种方式:

1、多平台代码放在一个类中

将win和linux各自的实现代码放在同一个类中,通过使用如下条件编译,来隔离不同平台的代码。

void Test1::doSomething()
{
#ifdef WIN32
    // ...
    QString str = "on Windows 10, doSomething!";
#else
    // ...
    QString str = "on Ubuntu 16.04, doSomething!";
#endif
    qDebug() << str;
}

此种方式只适合用于逻辑简单、代码较少的代码段,不适合用于大段代码跨平台,或者一个类中分布多个跨平台函数调用的情况,这样在整个类中,多个平台的代码缠绕在一起,会很混乱,难以维护。

大段代码,以及跨平台逻辑复杂,还是建议写在不同的文件中,以文件为界,来对不同平台代码进行隔离。

2、使用接口进行统一

先定义需要获取的功能接口,然后分别派生出win、linux下的子类,并在子类中完成各自平台的逻辑代码。如下:

定义ISysInfo接口(ISysInfo.h)

class ISysInfo
{
public:
    virtual QString getSystemName() = 0;
};

定义Linux下获取系统名称实现类(SysInfoLinux.h)

#ifndef SYSINFOLINUX_H
#define SYSINFOLINUX_H

#ifdef __linux

#include "ISysInfo.h"

class SysInfoLinux : public ISysInfo
{
public:
    virtual QString getSystemName() override
    {
        return "Ubuntu 16.04";
    }
};

#endif

#endif // SYSINFOLINUX_H

定义Win下获取系统名称实现类(SysInfoWin.h)

#ifndef SYSINFOWIN_H
#define SYSINFOWIN_H

#ifdef WIN32

#include "ISysInfo.h"

class SysInfoWin : public ISysInfo
{
public:
    virtual QString getSystemName() override
    {
        return "Windows 10";
    }
};

#endif

#endif // SYSINFOWIN_H

定义Test2类,Test2.h

#include "ISysInfo.h"

class Test2
{
public:
    Test2();
    ~Test2();

    void doSomething();

private:
    ISysInfo* sysInfo;
};

Test2.cpp

#include "Test2.h"
#include <QDebug>
#ifdef WIN32
#include "SysInfoWin.h"
#else
#include "SysInfoLinux.h"
#endif

Test2::Test2()
{
#ifdef WIN32
    sysInfo = new SysInfoWin();
#else
    sysInfo = new SysInfoLinux();
#endif
}

Test2::~Test2()
{
    delete sysInfo;
    sysInfo = nullptr;
}

void Test2::doSomething()
{
    QString str = "on " + sysInfo->getSystemName() + ", doSomething!";
    qDebug() << str;
}

在main.cpp进行调用

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

    Test2 test2;
    test2.doSomething();

    return a.exec();
}

此种方式的好处在于,通过接口可以屏蔽各平台的实现细节,只要添加好条件编译#ifdef,则调用时不需要关心到底调用的哪个类。

缺点在于,需要在调用者,代码中添加条件编译#ifdef,并需要管理linux和win实现类对象的生命周期。另外,SysInfoWin类需要添加条件编译#ifdef WIN32,SysInfoLinux类需要添加条件编译#ifdef __linux,否则编译出错,较为麻烦。

3、使用目录进行隔离

我们分别建立win目录和linux目录,分别存放各自平台实现代码,并且源文件名称保持一致SysInfo.h。如下:

在这里插入图片描述

然后在pro文件中,添加如下内容,对win/linux进行跨平台条件编译。

win32 {
    HEADERS += Test3/win/SysInfo.h
    INCLUDEPATH += Test3/win
} else {
    HEADERS += Test3/linux/SysInfo.h
    INCLUDEPATH += Test3/linux
}

随后,实现linux目录下SysInfo.h内容,如下:

class SysInfo
{
public:
    QString getSystemName()
    {
        return "Ubuntu 16.04";
    }
};

实现win目录下SysInfo.h内容,如下:

class SysInfo
{
public:
    QString getSystemName()
    {
        return "Windows 10";
    }
};

Test3.cpp中

#include "Test3.h"
#include <QDebug>
#include "SysInfo.h"

void Test3::doSomething()
{
    SysInfo info;
    QString str = "on " + info.getSystemName() + ", doSomething!";
    qDebug() << str;
}

在main.cpp中调用

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

    Test3 test3;
    test3.doSomething();

    return a.exec();
}

此种方式,通过在工程文件pro中,根据平台添加参与编译的源文件,实现跨平台编译。

使得调用者,无需关心到底#include "SysInfo.h"文件是哪个平台,由于pro中设置的关系,当include时会自动找到正确的平台头文件。在代码中不再使用#ifdef条件编译。

而且,与第2种对比,win和linux目录下SysInfo类不需要添加各自平台的条件编译宏Win32、__linux。所以应该是更方便的。

缺点,是必须手动人工,保证win和linux目录下SysInfo中,QString getSystemName()函数的一致性,否则在其他平台编译时,就可能出现报错。

三、总结

在实际操作中,我感觉还是推荐使用第3种使用目录进行隔离的方式,

虽然有缺点,但是只要在需要跨的平台上编译通过,基本就没有大问题,编译期,接口一致性还是容易解决。

另外在小段代码需要跨平台处理时,推荐使用第1种方式

当然在跨平台编程中,还有许多的注意点,以后有机会再继续分享。



若对你有帮助,欢迎点赞、收藏、评论,你的支持就是我的最大动力!!!

同时,阿超为大家准备了丰富的学习资料,欢迎关注公众号“超哥学编程”,即可领取。

本文涉及工程代码,公众号回复:17CrossPlatform,即可下载。

在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

百里杨

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

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

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

打赏作者

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

抵扣说明:

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

余额充值