C++中的常用接口
2022-01-15
4 min read
C++中的常用接口
目的
某一模块开发完成后,需要提供一个对外接口,让模块代码与调用者代码可以独立变化而互不影响,同时也能隐藏模块的实现细节;
pImpl技法
当自己的模块进行升级时,若接口类中成员变量发生变化,那么调用者的代码就需要重新编译,这种情况应该极力避免,因此需要一种方法来消除模块之间的编译依赖,降低耦合性;
在C++中,对于上述问题,pImpl 惯用技法(pointer to implementation idiom)被广泛使用。其具体做法是:实现细节的类不对外开放,在接口中仅仅存放实现类的指针,以隔离接口与实现,当实现变化时,只要被调用的接口函数形式不变,调用者代码就不会受到影响,无需重新编译。示例代码如下所示:
接口头文件代码(只有此头文件提供给调用者,其他文件均不对外开放):
// ----------------------------------------------------------------------------
/**
* @file Demo.h
* @note 本接口中所有函数应为公有,不应存在私有函数
*/
class Demo {
public:
Demo();
~Demo();
double foo(const double x);
private:
class DemoImpl;
DemoImpl* m_pImpl;
};
接口的cpp文件代码:
// ----------------------------------------------------------------------------
/**
* @file Demo.cpp
*/
#include "Demo.h"
#include "DemoImpl.h"
Demo::Demo() : m_pImpl( new Demo() ) {}
Demo::~Demo()
{
if (m_pImpl) {
delete m_pImpl;
}
}
double Demo::foo(const double x)
{
return m_pImpl->foo(x);
}
具体实现头文件代码:
// ----------------------------------------------------------------------------
/**
* @file DemoImpl.h
*/
class DemoImpl {
public:
DemoImpl() = default;
double foo(const double x);
private:
double operateOf(const std::vector<double>& bar, const double x);
// ...
private:
std::vector<double> m_bar;
};
具体实现的cpp文件代码:
// ----------------------------------------------------------------------------
/**
* @file DemoImpl.cpp
*/
#include "DemoImpl.h"
double DemoImpl::foo(const double x)
{
// ...
double y = this->operateOf(m_bar, x);
// ...
}
double DemoImpl::operateOf(std::vector<double>& bar, const double x)
{
// ...
}
调用者代码:
#include "Demo.h"
int main()
{
Demo demo;
double x = 0.0;
double y = demo.foo(x);
// ...
return 0;
}
其他形式接口
C语言接口
由于各语言一般都支持调用C接口,所以C++实现的模块提供C接口是最为通用的,而C++与C语言有着紧密的联系,故其导出为C接口十分方便,其示例代码如下:
// ----------------------------------------------------------------------------
/**
* @file foo.h
*/
#ifdef _cplusplus
extern "C" {
#endif
double foo(double x);
#ifdef _cplusplus
}
#endif
// ----------------------------------------------------------------------------
/**
* @file foo.cpp
*/
#include "foo.h"
#include "Demo.h"
double foo(double x)
{
Demo demo;
double y = demo.foo(x);
return y;
}
纯虚接口
还有一种接口方式就是纯虚接口,即设计一个纯虚类作为接口,让模块中具体实现类均继承此类,其优点是当模块中要添加新的类时,只需新的类成为纯虚类的子类即可,而调用者代码无需修改,降低了模块间的耦合;
其典型实现与前述文章中 工厂模式 类似,故不在此处赘述,若要详细了解,可参考前述文中代码;
总结
在C++开发中,常需要避免模块间的编译依赖,惯用方式为 pImpl 技法;
若要模块接口更为通用,可使用C接口;
而纯虚接口常用于面向对象设计中的多态需求;
实践中,根据不同要求,需恰当使用这些接口,以降低模块间耦合性;
版权声明:
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明出处!