1.簡介
這個(gè)機(jī)制是Private Implementation的縮寫眠寿,我們常常聽到諸如“不要改動(dòng)你的公有接口”這樣的建議躬翁,所以我們一般都會(huì)修改私有接口,但是這會(huì)導(dǎo)致包含該頭文件的所有源文件都要重新編譯盯拱,這會(huì)是個(gè)麻煩事兒盒发。Pimpl機(jī)制,顧名思義狡逢,將實(shí)現(xiàn)私有化宁舰,力圖使得頭文件對(duì)改變不透明配阵。
2.機(jī)制分析
首先某宪,我們先看看不使用這個(gè)機(jī)制的一個(gè)實(shí)現(xiàn):
// MyBase.h
class MyBase {
public:
int foo();
};
// MyDerived.h
#include "MyBase.h"
class MyDerived : public MyBase {
public:
int bar();
};
假設(shè)你現(xiàn)在希望在MyBase.h中加入一個(gè)新的private和protected成員函數(shù),那么MyDerived和所有包含MyBase.h的源文件都需要重新編譯拒担。在一個(gè)大工程中殷费,這樣的修改可能導(dǎo)致重新編譯時(shí)間的激增印荔。你可以使用Doxygen或者SciTools看看頭文件依賴。
一般來說详羡,不在頭文件中包含頭文件是一個(gè)比較好的習(xí)慣仍律,但是這也不能完全消除修改MyBase.h帶來的重新編譯代價(jià)。有沒有一個(gè)機(jī)制可以使得對(duì)私有接口做修改時(shí)我們可以減小重新編譯的代價(jià)实柠。
在Pimpl機(jī)制中水泉,我們使用前置聲明一個(gè)Impl類,并將這個(gè)類的一個(gè)指針實(shí)例放入主類中窒盐,如下:
// MyClass.h
class MyClassImpl; // forward declaration
class MyClass {
public:
MyClass();
~MyClass();
int foo();
private:
MyClassImpl *m_pImpl;
};
現(xiàn)在草则,除非我們修改MyClass的公有接口,否則這個(gè)頭文件是不會(huì)被修改了蟹漓。然后炕横,我們用這個(gè)Impl類的實(shí)現(xiàn)來完成主類的細(xì)節(jié)實(shí)現(xiàn),在主類的構(gòu)造函數(shù)中葡粒,我們完成了實(shí)現(xiàn)類指針的實(shí)例化:
// MyClass.cpp
class MyClassImpl {
public:
int foo() {
return bar();
}
int bar() {
return var++;
}
int var;
};
MyClass::MyClass() : m_pImpl(new MyClassImpl){}
MyClass::~MyClass()
{
try {
delete m_pImpl;
}
catch (...) {}
}
int MyClass::foo(){ return m_pImpl->foo(); }
Pimpl機(jī)制其實(shí)這是橋接模式的一種變種份殿。我們可以對(duì)實(shí)現(xiàn)類隨意的進(jìn)行增刪和修改,而不會(huì)導(dǎo)致包含MyClass.h的源代碼重新編譯嗽交。當(dāng)然卿嘲,這樣做的時(shí)間開銷和空間開銷也是有的。
在實(shí)踐中夫壁,我們常常采用內(nèi)部類來完成Pimpl機(jī)制:
// header
class fruit
{
public:
private:
class impl;
impl* pimpl_;
}
// implementation
class fruit::impl
{
};
fruit::fruit()
{
pimpl_ = new impl();
}