PIMPL 模式的实现及应用

 

pImpl惯用手法的运用方式大家都很清楚,其主要作用是解开类的使用接口和实现的耦合。如果不使用pImpl惯用手法,代码会像这样:

       //c.cc

        #include<x.h>

        class C

        {

        public:

            void f1();

        private:

            X x; //X的强耦合

        };

 

像上面这样的代码,类C与它的实现就是强耦合的,从语义上说,x成员数据是属于C的实现部分,不应该暴露给用户。从语言的本质上来说,在用户的代码中,每一次使用”new C””C c1”这样的语句,都会将X的大小硬编码到编译后的二进制代码段中(如果X有虚函数,则还不止这些)——这是因为,对于”new C”这样的语句,其实相当于operator new(sizeof(C) )后面再跟上C的构造函数,而”C c1”则是在当前栈上腾出sizeof(C)大小的空间,然后调用C的构造函数。因此,每次X类作了改动,使用c.cc的源文件都必须重新编译一次,因为X的大小可能改变了。

在一个大型的项目中,这种耦合可能会对build时间产生相当大的影响。

pImpl惯用手法可以将这种耦合消除,使用pImpl惯用手法的代码像这样:

//c.cc

        class X; //用前导声明取代include

        class C

        {

         ...

         private:

            X* pImpl; //声明一个X*的时候,class X不用完全定义

        };

 

在一个既定平台上,任何指针的大小都是相同的。之所以分为X*Y*这些各种各样的指针,主要是提供一个高层的抽象语义,即该指针到底指向的是那个类的对象,并且,也给编译器一个指示,从而能够正确的对用户进行的操作(如调用X的成员函数)决议并检查。但是,如果从运行期的角度来说,每种指针都只不过是个32位的长整型(如果在64位机器上则是64位,根据当前硬件而定)。

正由于pImpl是个指针,所以这里X的二进制信息(sizeof(C)等)不会被耦合到C的使用接口上去,也就是说,当用户”new C””C c1”的时候,编译器生成的代码中不会掺杂X的任何信息,并且当用户使用C的时候,使用的是C的接口,也与X无关,从而X被这个指针彻底的与用户隔绝开来。只有C知道并能够操作pImpl成员指向的X对象。

测试用例:

//cls.h

#ifndef _CLS_H
#define _CLS_H

#include<iostream>
#include<memory>

class CMyClass
{
public:
	CMyClass(int i = 0);
	~CMyClass(void);
public:
	void Print();

private:
	int m_iData;
};

#endif


//c.cc

#include"cls.h"

CMyClass::CMyClass(int i):m_iData(i)
{

}

CMyClass::~CMyClass(void)
{
}

void CMyClass::Print()
{
	std::cout << "CMyClass::print "<< m_iData <<std::endl;
}


//pmipl.h

#ifndef _PMIMPL_
#define _PMIMPL_

#include<iostream>
#include<memory>

class CMyClass;
 
class CPimpl
{
public:
	CPimpl(int i = 0);
	~CPimpl(void);
public:
	void Print();
private:
	std::auto_ptr<CMyClass> ptr_mCls;
};

#endif


//pmiph.cc

#include "pimpl.h"
#include"cls.h"

CPimpl::CPimpl(int i):ptr_mCls(new CMyClass(i))
{

}

CPimpl::~CPimpl(void)
{

}

void CPimpl::Print()
{
	ptr_mCls->Print();
}


//main.cc

#include "pimpl.h"
int main(int argc,char *argv[])
{
	CPimpl pl(8);
	pl.Print();
}


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值