PIMPL机制学习

pimpl 用法背后的思想是把客户与所有关于类的私有部分的知识隔离开。由于客户是依赖于类的头文件的,头文件中的任何变化都会影响客户,即使仅是对私有节或保护节的修改。pimpl用法隐藏了这些细节,方法是将私有数据和函数放入一个单独的类中,并保存在一个实现文件中,然后在头文件中对这个类进行前向声明并保存一个指向该实现类的指针。类的构造函数分配这个pimpl类,而析构函数则释放它。这样可以消除头文件与实现细节的相关性。

---------摘自《超越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.

----- 摘自《Exceptional c++》

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

CSDN blog:http://blog.csdn.net/ma12an/article/details/7491893



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值