PIMPL模式设计实现

Pimpl(Pointer to implementation)是针对C++的设计模式Q,它将所有的私有数据成员、私有成员函数隔离到一个.cpp文件中独立实现的类或结构体内。


首先观察一个没有使用Pimpl的例子:

这里有三个文件,foo.h与foo.cpp用于声明CFoo类。main.cpp调用该类,并使用类中的ProcessFile方法。在现实场景中,开发人员在foo.h与foo.cpp实现foo类别的功能,用户通过main函数调用API。

/*File foo.h*/
class CFoo
{
public:
    CFoo();
    ~CFoo();
    bool ProcessFile(const CString & csFile);
private:
    CFooInternalData    m_data;
    CHeader             m_header;
}
 

/*File foo.cpp*/
#include "FooInternalData.h"
#include "Header.h"
#include "foo.h"
 
CFoo::CFoo()
{
}
 
CFoo::~CFoo()
{
}
 
bool CFoo::ProcessFile(const CString & csFile)
{
    //do something
    return true;
}
 
/*File main.cpp*/
#include "FooInternalData.h"
#include "Header.h"
#include "foo.h"
 
int main()
{
    CFoo foo;
    foo.ProcessFile("c:\\data.bin");
    return 0;
}

我们希望用户只需要#include "foo.h"即可使用CFoo类的各种功能,但是发现main函数不但要调用foo.h,还需要调用FooInternalData.h与Header.h,因为在CFoo类的具体实现中用到了这两个头文件。这样的设计存在以下问题:

1.头文件的增多会导致编译速度变慢。

2.CFoo类与 CFooInternalData紧紧绑定,只要CFooInternalData发生改变,CFoo类就需要重新编译。


回看刚刚的代码,CFooInternalData和CHeader数据类型需要包含FooInternalData.h与Header.h才能访问的,但是CFoo类中是私有的(private)。换句话说,用户在main函数中自己是用不到这两个数据类型的(因为对他们的数据操作全部封装在了foo.h中)。既然如此,我们希望用户在main函数中也不需要包含这两个头文件。

因此我们就引出了PIMPL设计方法。该方法目的是将所有的私有成员隐藏在.cpp中,这样用户在main函数中就不需要包含相关的头文件了。具体思想是将私有成员(例如CFoo类中private部分的数据和函数)放置在一个类(结构体)中,原始的类通过指针访问封装了私有成员的新结构体。

以下是需要的操作(文章最下面有完整的代码):

首先在foo.h中,只需要声明一个PIMPL类用于编译。public部分和之前没有修改,private私有成员部分,定义了一个自动指针,std::auto_ptr<CFoo_pimpl>    m_pImpl,后面将通过调用自动指针来进行原来私有成员需要的操作。

/*File foo.h*/
class CFoo_pimpl; //前置声明
 
class CFoo
{
public:
    CFoo();
    ~CFoo();
    bool ProcessFile(const CString & csFile);
private:
    std::auto_ptr<CFoo_pimpl>    m_pImpl;
} 

在foo.cpp中,给出了上面foo.h中声明的CFoo_pimpl类的结构与定义。可以看出,这里的CFoo_pimpl类就和我们最上面非PIMPL方法的CFoo类一模一样。

同时该文件中也定义了CFoo类的成员,因为功能都是在CFoo_pimpl类中实现的,所以CFoo类只是调用CFoo_pimpl类方法,从而实现了对代码的封装。

/*File foo.cpp*/
#include "FooInternalData.h"
#include "Header.h"
#include "foo.h"
 
 
//定义PIMPl类
class CFoo_pimpl()
{
public:
    CFoo_pimpl()
    {
    }
 
    ~CFoo_pimpl()
    {
    } 
    bool ProcessFile(const CString & csFile)
    {
        //do something
        return true;
    }
private:
    CFooInternalData    m_data;
    CHeader             m_header;
};


//定义CFoo类中的成员 
CFoo::CFoo()
:m_pImpl(new CFoo_pimpl())
{
}
 
CFoo::~CFoo()
{
    //为空即可,std::auto_ptr可以自动析构
}
 
bool CFoo::ProcessFile(const CString & csFile)//通过调用pImpl类中的方法实现
{
    //just call your PIMPL function ;-)
    return m_pImpl->ProcessFile(csFile);
}

最后用户在调用foo.h时,就不需要包含CFoo类内部私有成员所需的头文件啦。(*^▽^*)

/File main.cpp*/
#include "foo.h"
 
int main()
{
    CFoo foo;
    foo.ProcessFile("c:\\data.bin");
    return 0;
}

参考内容:

API Design for C++之Pimpl设计模式_GarryLau的博客-CSDN博客

PIMPL模式的实现及应用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值