SDK(动态链接库dll)的封装技巧

SDK(动态链接库dll)的封装技巧

一、说明

通过上篇文章,我们知道对于封装API,目的为了代码复用等,其中还有一个重要的原因,就是隐藏实现。

 说到隐藏实现,在封装C++的SDK库(动态dll库)时,可以使用Pimpl的方式来实现。 

二、Pimpl

Pimpl是“pointer to implementation”的缩写,目的就是避免在头文件中暴露私有细节

PimplC++ 在构建导出库接口时特有的技术手段。 即是将类中所有私有变量以及私有方法,封装在一单独的实现私有类中。我们在中通过一指向私有类的私有指针,访问这些私有数据。而私有类的具体定义和实现,放入cpp文件中

Qt中的D指针就是Pimpl方式的实现

我们还以上节的代码来举例。

比如,我想提供几个接口函数,来实现一个计算,通过数据两个参数,我输出一个计算值。如下所示:


#ifndef EXAMPLEDLL_H
#define EXAMPLEDLL_H
 
#include "exampledll_global.h"
 
class EXAMPLEDLLSHARED_EXPORT ExampleDLL
{
 
public:
    ExampleDLL();

    int calculation(int a, int b);
 
    int add(int a, int b);
 
    int subtract(int a, int b);
 
    int multiply(int a, int b);
 
    int divide(int a, int b);
};
 
#endif // EXAMPLEDLL_H

这个calculation函数的实现如下:

#include "exampledll.h"
 
 
ExampleDLL::ExampleDLL()
{
}

int ExampleDLL::calculation(int a, int b)
{
    int x = 0;
    x = add(a,b) + subtract(a,b) + multiply(a,b) + divide(a,b);
    return ( x);
}
 
int ExampleDLL::add(int a, int b)
{
    return ( a + b );
}
 
int ExampleDLL::subtract(int a, int b)
{
    return ( a - b );
}
 
int ExampleDLL::multiply(int a, int b)
{
    return ( a * b );
}
 
int ExampleDLL::divide(int a, int b)
{
    return ( a / b );
}

计算的结果是add(a,b) + subtract(a,b) + multiply(a,b) + divide(a,b);四个函数的相加得来的。

如果,我不想让别人看到,我这个函数里面使用了add(a,b) 、 subtract(a,b) 、 multiply(a,b) 、 divide(a,b)这几个函数。只给使用者暴露int calculation(int a, int b)函数。那么此时,我们就可以使用pimpl模式来封装我们的类了。

三、Pimpl的封装形式

在头文件中


#ifndef EXAMPLEDLL_H
#define EXAMPLEDLL_H
 
#include "exampledll_global.h"
 
class EXAMPLEDLLSHARED_EXPORT ExampleDLL
{
 
public:
    ExampleDLL();

    int calculation(int a, int b);

private:
    class ContextPointer;
    ContextPointer *d_ptr;
};
 
#endif // EXAMPLEDLL_H

cpp文件:

#include "exampledll.h"
 
class ExampleDLL::ContextPointer
{
public:
    int add(int a, int b);
 
    int subtract(int a, int b);
 
    int multiply(int a, int b);
 
    int divide(int a, int b);

};


ExampleDLL::ExampleDLL()
{
    d_ptr = new ContextPointer();
}

int ExampleDLL::calculation(int a, int b)
{
    int x = 0;
    x = d_ptr->add(a,b) + d_ptr->subtract(a,b) + d_ptr->multiply(a,b) + d_ptr- 
        >divide(a,b);

    return ( x);
}
 
int ExampleDLL::ContextPointer::add(int a, int b)
{
    return ( a + b );
}
 
int ExampleDLL::ContextPointer::subtract(int a, int b)
{
    return ( a - b );
}
 
int ExampleDLL::ContextPointer::multiply(int a, int b)
{
    return ( a * b );
}
 
int ExampleDLL::ContextPointer::divide(int a, int b)
{
    return ( a / b );
}

如上所示,这样我们就把想要隐藏的代码给隐藏了。

四、优缺点

优点:

1、数据隐藏,非常适合隐藏private实现,如果想要在头文件中暴露public接口,但又不想暴露private实现的细节,使得头文件很干净,可以直接作为API参考。

2、pimpl又被称为编译防火墙。是一种缩短编译时间,降低程序编译依赖的方法。因为,如果头文件里的内容变了,意味着引用该头文件的代码都要被重新编译。如果把这些变动的内容放到只被引用编译一次的源文件中,就不会耗费太多的编译时间。

3、是程序接口有着稳定的ABI(应用程序二进制接口),即不会打破二进制兼容。

缺点:

1、由于数据的隐藏方式,代码的可读性会下降。

2、可能会降低程序的性能,比如调用的函数为虚函数的时候。

注:二进制兼容:在升级库文件的时候,不必重新编译使用此库的可执行文件或其他库文件,并且程序的功能不被破坏,能正常运行。即如果exe调用dll库时,dll库更新了,exe不用重新编译也能正常运行。

上一篇:Qt创建SDK库(dll动态库)并调用SDK库(dll动态库)

下一篇:

本文原创作者:冯一川(ifeng12358@163.com),未经作者授权同意,请勿转载。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

冯一川

谢谢老板对我的支持!

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

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

打赏作者

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

抵扣说明:

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

余额充值