> 文章列表 > SDK(动态链接库dll)的封装技巧

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

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

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

一、说明

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

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

二、Pimpl

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

Pimpl是C++ 在构建导出库接口时特有的技术手段。 即是将类中所有私有变量以及私有方法,封装在一单独的实现私有类中。我们在中通过一指向私有类的私有指针,访问这些私有数据。而私有类的具体定义和实现,放入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不用重新编译也能正常运行。

上一篇:

下一篇:

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