Qt动态库封装工程最佳实践

本文详细介绍了如何在Qt环境下创建并生成动态链接库(DLL),包括设置工程目录、导出类和结构体,以及如何测试DLL。通过实例展示了如何封装类和结构体,以减少对外接口的暴露,提高代码封装性。最后,演示了在新的Qt控制台应用中调用生成的DLL并验证其功能。
摘要由CSDN通过智能技术生成

目录

1、建立并生成动态链接库

2、导出类工程目录

3、测试生成的DLL


验证环境:Win10+Qt5.14

验证内容:Qt导出类。

1、建立并生成动态链接库

1、打开QtCreator,新建工程,我们选择Library,C++库,然后就是choose。

2、然后在弹出的C++库对话框我们默认类型共享库,名称为MyDll。然后,一直下一步,直到点击完成。

3、生成的代码结构

        MyDll.pro

QT       -= gui # 不需要界面

TARGET = MyDll #工程名
TEMPLATE = lib # 生成lib

DEFINES += MYDLL_LIBRARY # 预定义宏
DEFINES += QT_DEPRECATED_WARNINGS

SOURCES += \
        mydll.cpp

HEADERS += \
        mydll.h \
        mydll_global.h 

unix {
    target.path = /usr/lib
    INSTALLS += target
}

        mydll_global.h中,内容如下:

#ifndef MYDLL_GLOBAL_H
#define MYDLL_GLOBAL_H

#include <QtCore/qglobal.h>

#if defined(MYDLL_LIBRARY)
#  define MYDLLSHARED_EXPORT Q_DECL_EXPORT
#else
#  define MYDLLSHARED_EXPORT Q_DECL_IMPORT
#endif

#endif // MYDLL_GLOBAL_H

        可以看到系统自动定义了两个宏。用于声明哪些函数是需要我们导出的。

2、导出类工程目录

        以工程导出mydll.dll为例。Mydll类中包含ClassA、ClassB两个类的支持,并在Mydll类的接口中需要引用ClassA/ClassB中定义的结构体structA/structB。如果将两个Class定义在mydll.h中,提供动态库时则必须同时提供这两个类的头文件,比较繁琐,也不利于封装。

好的做法是:

        1)将ClassA、ClassB及其它更多类的支持封装在一个公共类中,在接口类中定义该公共类指针,用于ClassA、ClassB类对象的访问;

        2)将需要暴露出来的结构体,进行整体封装,写入mydll.h头文件中,之后在mydll.cpp的函数体内进行解析为对应的结构体。或者将公共部分抽象为公共头文件。

具体实践:

        classa.h定义,定义结构体structA,并使用其进行初始化。

#ifndef CLASSA_H
#define CLASSA_H
#include <iostream>

struct structA
{
    structA() {}
    int a;
};

class ClassA
{
public:
    ClassA();
    void init(structA &a) { std::cout<<"ClassA init."<<std::endl; }
    void run()  { std::cout<<"ClassA run()."<<std::endl; }
};

#endif // CLASSA_H

        classb.h定义,定义结构体structB,并使用其进行初始化。

#ifndef CLASSB_H
#define CLASSB_H
#include <iostream>

struct structB
{
    structB() {}
    float b;
};

class ClassB
{
public:
    ClassB();
    void init(structB &b) { std::cout<<"ClassB init."<<std::endl; }
    void run()  { std::cout<<"ClassB run()."<<std::endl; }
};

#endif // CLASSB_H

接口类定义:

        1)接口类头文件定义,mydll.h:

#ifndef MYDLL_H
#define MYDLL_H
#include "mydll_global.h" 

struct structC //公共头文件,封装所需参数,对外接口
{
    structC() {}
    int a;
};

class MYDLLSHARED_EXPORT Mydll
{

public:
    Mydll();
    ~Mydll();

    int init(structC &a); // 输出公共结构体参数,函数内解析适配ClassA、ClassB。
    int run();

private:
    // 声明封装类DetImp,并定义该类指针_detImp,此时DetImp类并未定义。
    class DetImp; 
    DetImp *_detImp;
};

#endif // MYDLL_H

        2)接口类源文件定义,mydll.cpp:

#include "mydll.h"
#include "classa.h" // .cpp中引用classa.h,不必暴露在接口中
#include "classb.h"
#include <iostream>

class Mydll::DetImp  // 接口类中DetImp类实现,只做其它类封装。
{
public:
    DetImp(){}
    ~DetImp(){}
    ClassA m_clsa;
    ClassB m_clsb;
};

Mydll::Mydll() // 构造函数中做公共类初始化
{
    _detImp = new DetImp();
    std::cout<<"init Mydll, create _detImp."<<std::endl;
}

Mydll::~Mydll() // 析构函数中做公共类析构
{
    if (_detImp)
    {
        delete _detImp;
        _detImp = nullptr;
    }
}

int Mydll::init(structC &c) // init中做参数解析适配,根据关系调用对应子类。
{
    std::cout<<"Mydll init."<<std::endl;
     structA a;
    _detImp->m_clsa.init(a);

    structB b;
    _detImp->m_clsb.init(b);
    return 0;
}

int Mydll::run()
{
    std::cout<<"Mydll run."<<std::endl;
    _detImp->m_clsa.run();
    return 0;
}

        编译,生成动态库。

3、测试生成的DLL

1、新建一个基于Qt的控制台应用程序,名称为DllTest,与MyDll放在同一级目录下。

2、建好了以后,就可以进行调用验证了。

        调用编译好的动态库需要引用两个东西:动态库的头文件和动态库文件。

        1)在.pro中添加对Lib的引用

LIBS += -L$$PWD/../build-mydll-Desktop_Qt_5_14_2_MSVC2017_64bit-Release/release/ -lmydll

        2)在引用文件中,添加头文件的引用

#include "../mydll/mydll.h"

        main.cpp调用完整代码:

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

    Mydll mydll = Mydll();
    structC c;
    mydll.init(c);
    mydll.run();

    return a.exec();
}

        输出结果:

上一篇:Qt创建使用动态链接库工程,下一篇:Qt在命名空间中导出类和函数

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

jingbo1801

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

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

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

打赏作者

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

抵扣说明:

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

余额充值