PIMPL 模式的实现及应用。

看一些开源库,里面好多类有一个**IMPL。经查询还是有些门道和说法的。查询了一些相关资料。(英文没有翻译,挺简单的。)

PIMPL 也可以称为一种设计模式了。

现在摘录如下:

pimpl 手法在 C++ 里已是“高手”们广泛运用的成熟方法之一,它的优点很多,诸如降低编译依赖、提高重编译速度之类的工具性优势自不待赘言,而其对“保持接口稳定性”的优点更值得称道。

It makes it possible to avoid other classes to know internal data structures and other information of the class. It also simplifies some #includepreprocessor instructions.避免别的class知道其内部的数据结构。还可以简化预编译指令。

下面是一个Example WITHOUT PIMPL 。

如下:

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;
}

Main File

#include "FooInternalData.h"

#include "Header.h"

#include "foo.h"


int main()
{
    CFoo foo;
    foo.ProcessFile("c:\\data.bin");
    return 0;
} 

   The problem with this simple way of coding is that in your main file, you must include the foo.h to use it, but at the same time you must also include all needed files to allow the compiler to work correctly. In fact, the main does not need to include FooInternalData.h and Header.h (which are CFoo internal structures) except for compilation.... So with very big classes, you might do some huge includes and in this case, you can have some compiler or linker errors because files are already included elsewhere.

以上代码有些不足:

第一,引入更多的头文件降低编译速度。而且这个声明当然写在一个头文件里,而头文件,是不能预编译或增量编译的,如果你因此而引入一个诸如<windows.h>之类的头文件,产生的代价可能是一杯咖啡的编译时间--而且每次编译都这样;
第 二,大大提高的模块的耦合度。在这里,CFooInternalData从此与 CFoo紧紧绑定。在一个库里的模块互相耦合当然可以忍受,不过你要记得,这里有两种耦合度:一个是编译期的,一个是运行期的,这种方式下,无论编译还是运行,它 们都耦合在一起,只要 CFooInternalData 发生变更,CFoo 的模块也必须重新编译;
第三,降低了接口的稳定程 度。接口的稳定,至少有两个方面:一个是对于库的运用,即方法调用不能变;一个是对于库的编译,即动态库的变更最好能让客户程序不用重编译。方法调用与这 个问题无关,但对于库的编译,如果CFooInternalData 变了,客户程序显然必须重新编译,因为 private 部分,虽然对于客户程序不可用,但并不是不可见,尤其是对编译器来说。对于一个动态链接库,这个问题可能会让人无法忍受。

pimpl 手法能比较完善的解决这些问题。利用 pimpl 手法,我们把数据细节隐藏到一个实现类里:CFoo_pimpl,而 CFoo 的 private 部分只剩下一个指针,那就是传说中滴 pimpl 指针

The Same Example with PIMPL

File foo.h


//here just declare the class PIMPL to compile. 
//As I use this class with a pointer, I can use this declaration 
class CFoo_pimpl; 

class CFoo
{
public:
    CFoo();
    ~CFoo();
    bool ProcessFile(const CString & csFile);
private:
    std::auto_ptr<CFoo_pimpl>    m_pImpl;
}  

File foo.cpp


#include "FooInternalData.h"

#include "Header.h"

#include "foo.h"


//here defines PIMPl class, because it is use only in this file
class CFoo_pimpl()
{
public:
    CFoo_pimpl()
    {
    }

    ~CFoo_pimpl()
    {
    }  
    bool ProcessFile(const CString & csFile)
    {
        //do something
        return true;
    }
};

CFoo::CFoo()
:m_pImpl(new CFoo_pimpl())
{
}

CFoo::~CFoo()
{
    //do not have to delete, std::auto_ptr is very nice 
}

bool CFoo::ProcessFile(const CString & csFile)
{
    //just call your PIMPL function ;-)
    return m_pImpl->ProcessFile(csFile);
}

Main File


#include "foo.h"

int main() 
{
    CFoo foo;
    foo.ProcessFile("c:\\data.bin");
    return 0; 
} 

 

The result is obvious: simplicity of use!! The main does not need more includes for internal structures of CFoo class.

Thus it is an excellent optimization to minimize linker and compiler errors.

Conclusion

It is a very simple and nice way for good coding!!! If you want to use classes in other projects, it does not introduce including difficulties.

Unfortunately, you must add some more code to type.

代码来自:www.codeproject.com.

本文版权归作者 kanego 和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利.
posted @ 2011-11-23 19:05  kanego  阅读(11684)  评论(5编辑  收藏  举报