---------摘自《超越c++标准库——boost程序库导论》
C++ lets us easily encapsulate the private parts of a class from unauthorized access. Unfortunately, because of the header file approach inherited from C, it can take a little more work to encapsulate dependencies on a class's privates. "But," you say, "the whole point of encapsulation is that the client code shouldn't have to know or care about a class's private implementation details, right?" Right, and in C++, the client code doesn't need to know or care about access to a class's privates (because unless it's a friend, it isn't allowed any), but because the privates are visible in the header, the client code does have to depend upon any types they mention.
PIMPLl字面解释:
1.Private Implementation直接的字面意思就是“实现私有化”,也如我们常常听到诸如“不要改动你的公有接口”这样的建议,Pimpl机制,顾名思义,将实现私有化,力图使得头文件对改变不透明。主要作用是解开类的使用接口和实现的耦合。
2.pointer to implementation
这种说法语义上更关注代码的实现方法,也就是一个指向实现的指针,Pimpl 仅仅是一个opaque pointer指针(a forward-declared, but undefined, helper class)用以隐藏private成员。即:// file x.h
class X
{
// public and protected members
private:
// private members; whenever these change,
// all client code must be recompiled
};
具体化:// file x.h
class X
{
// public and protected members
private:
struct XImpl;
XImpl* pimpl_;
// a pointer to a forward-declared class
};
// file x.cpp
struct X::XImpl
{
// private members; fully hidden, can be
// changed at will without recompiling clients
};
主要的好处:解耦了编译的依赖,
1)client如果使用此代码,在private members改变的时候,不需要重新编译client代码
2)只声明了类,减少了头文件(extra #include),以此提高了编译的速度。
在性能上的开销:
1)对于每个构造和析构函数,需要分配内存,需要对opaque pointer指针进行管理。通常使用auto_ptr或者shared_ptr来管理
2)每一次获取hidden member需要至少一次额外的indirection开销。
实例:
//普通代码///
// 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;
}
/Attempt #1//
// 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:
CFoo_pimpl m_pImpl;
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()
{
delete CFoo_pimpl;
CFoo_pimpl = 0;
}
bool CFoo::ProcessFile(const CString & csFile)
{
//just call your PIMPL function ;
return m_pImpl->ProcessFile(csFile);
}
/Attempt #2//
// 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:
static const size_t sizeofn = /*some value*/
char m_pImpl[sizeofn];
}
//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()
{
assert(sizofn >= sizeof(CF_pimpl));
new (&m_pImpl[0]) CF_pimpl; //placement new; More Effective C++有详细解释Operator new, placement new, new;
}
CFoo::~CFoo()
{
(reinterpret_cast<X*>(&m_pImpl[0]))->~X();
}
bool CFoo::ProcessFile(const CString & csFile)
{ //just call your PIMPL function ;-)
return m_pImpl->ProcessFile(csFile);
}
/Attempt #3//
// 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);
}
参考:
Exceptional C++: 47 Engineering Puzzles, Programming Problems, and Solutions
Codeprojec: http://www.codeproject.com/Articles/17536/Use-of-PIMPL-Design-Pattern
优快云 blog:http://blog.youkuaiyun.com/ma12an/article/details/7491893