C++开发sdk之PIMPL隐式开发

 

C++开发sdk之PIMPL隐式开发

一、前言

  • API的调用者只关注API的接口,并不关注实现API的实现,以及过程变量或函数
  • 如果api简单,尽可能只提供一个头文件+一个库给到API调用者,既隐藏隐私,也方便了API调用者
  • PIMPL:Pointer to implementation,由指针指向实现,而不过多暴露细节
  • 提供API库也需要提供调用API库的示例代码
  • C++习惯开发一个类对应一个类声明.h + 一个类实现.cpp

二、一般SDK开发示例

//test_api.h
#ifndef _TEST_API_H
#define _TEST_API_H

#incldue "test.h" //class Test
//可能还会包含其他的类,但用户都用不到的*.h

class TestApi{
  public:
    TestApi();
    ~TestApi();
    void TestPrint(); //用户需要的API
    //其他方法,有些方法可能只是做中转使用,对用户无意义
  private:
    Test * m_test;
    //其他私有成员,对用户无意义
};
#endif //_TEST_API_H

 

//test_api.cpp
#include test_api.h
#include test.h
//...

TestApi::TestApi()
{
    m_test = new Test();
}

~TestApi::TestApi()
{
    delete m_test;
}

voide TestApi::TestPrint()
{
    m_test->show();
}
//...
//test.h
#ifndef _TEST_H
#define _TEST_H

#include <iostream>
#include <stdio.h>

class Test{
public:
    Test(){

    }
    ~TEest(){
    
    }
    void show();
    //...
private:
    //...
};

#endif
//test.cpp

#include "test.h"

void Test::show()
{
    printf("i am Test::show()\n");
}
//等等方法的实现

编译动态库libtest_api.so:

    g++ -fPIC -c -o test_api.o test_api.cpp

    g++ -fPIC -c -o test.o test.cpp 

    g++ -fPIC -shared -o libtest_api.so test_api.o test.o

//用户调用库示例代码
//user.cpp

#include "test_api.h"
#include <iostream>
#include <stdio.h>

int main()
{
    TestApi api = new TestApi();
    api->TestPrint();
    delete api;
    return 0;
}

提供给用户的编译文件需要 testapi/include/test_api.h + testapi/include/test.h + testapi/lib/libtest_api.so + testapi/user.cpp;如果定义的类比较多,按C++习惯提供类头文件也就越多,暴露的对用户无意义的类文件就越多。

用户调用库编译:

    g++ -I~/testapi/include -L~/testapi/lib -o user user.cpp -ltest_api

 

三、PIMPL开发SDK

//test_api.h
#ifndef _TEST_API_H
#define _TEST_API_H

//#incldue "test.h" //不需要添加其他类的头文件
//可能还会包含其他的类,但用户都用不到的*.h

class TestApi{
  public:
    TestApi();
    ~TestApi();
    void TestPrint(); //用户需要的API

  private:
    class TestImpl;
    TestImpl * m_impl;

};
#endif //_TEST_API_H
//test_api.cpp
#include test_api.h
#include test.h
//其他类头文件

class TestApi::TestImpl
{
public:
    TestImpl();
    ~TestImpl();
    void Show();
    //其他中转成员函数
public:
    Test m_test;// class test
    //其他中转类或变量,建议声明为public方便调用~
};

TestApi::TestImpl::TestImpl()
{
    m_test = new Test();
}

TestApi::TestImpl::~TestImpl()
{
    delete m_test;
}

TestApi::TestApi()
{
    m_test = new Test();
}

~TestApi::TestApi()
{
    delete m_test;
}

void TestApi::TestImpl::Show()
{
    m_test->show();
}

void TestApi::TestPrint()
{
    m_impl->show();
    //or
    //m_impl->m_test->show(); //公有成员
}
//...

其他 test.cpp test.h user.cpp 保持不变,动态库编译方式以及user.cpp编译也一样,提供给用户必要文件就如下:testapi/include/test_api.h + testapi/lib/libtest_api.so + testapi/user.cpp (减少提供了test.h, 如果类多了,类的头文件就少的更多)

四、总结

从示例中,我们可以看到PIMPL式开发SDK有以下优点:

  1. 降低耦合,头文件稳定,类具体实现改变不影响其他模块的编译,只影响可执行程序的链接
  2. 接口和实现分离,提高稳定性
  3. 隐藏了类是声明,只提供对用户的API接口,对模块比较多sdk开发有一定的优势。

 

感谢原创的启发,参考于https://mp.weixin.qq.com/s/K5XjQONwOGhzfcCF-ci5Og?st=8E5821BCDA35A3F104C329D80F53A0F9B6E3EE172749E98064F198EC7E2DBA63EC91DFEE02A8542B80E54FBA8416FC29E4A1CAC56B6201462020A59EB33D0A5001121493393474300AC639ABB350D8D7D8A10DC1552F30130C60974E968BF12EB8C87E33FAAB7E977861D363C655F18C6691AA5A38FFCE752CB24EBFAB19DC41F34F802D2D1AA7AFDDA662CFEBAA3244373E1222ACFD15DBA18CCC4205B77B941A6FA38E21E4A5D423918A976EF4916188D412B7B9FF16DA0119CEB1A0EFEB92&vid=1688851056661113&cst=36C669FF062AA5B4F0A76680BF95CA8D26F5C031BC538E5F0C0D2B9DFF1F448D07C52A13ED904E7B1D47E72DCDEDA8BE&deviceid=5ffd9de1-093f-47d4-85e5-1620bb27d1c1&version=3.1.1.3006&platform=win

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值