C++必知必会:pimpl惯用法

前言

在日常开发中,类的public方法提供了对外接口供第三方使用,每个函数的具体实现都在XXX.cpp里,对第三方不可见。对于Windows系统上提供给第三方的库,库作者一般需要提供.h、.lib、.dll 文件给使用者,对于Linux系统则需要提供.h、.a、或 .so。

不管那种系统,提供像XXX.h这样的头文件给第三方使用时, .h文件中类的大量成员变量和私有函数都暴露了这个类的太多实现细节,很容易让使用者看出其实现原理。

示例

这个类中暴露了成员变量

class Object
{
public:
	Object();
	~Object();

private:
	char a;
	short b;
	int	c;
	long d;
	long long e;
	float f;
	double g;
};

使用pimpl惯用法之后

所有的关键成员变量都已经不存在了,取而代之的时一个类型为Impl的指针成员变量m_pImpl;

// 前置声明
class Impl;

class Object
{
public:
	Object();
	~Object();

private:
	Impl* m_pImpl;
};
class Impl
{
public:
	Impl()
	{
		// 可以做一些初始化工作
	}
	~Impl()
	{
		// 可以做一些清理工作
	}
public:
	char a;
	short b;
	int	c;
	long d;
	long long e;
	float f;
	double g;
};

接着在.cpp文件中,Object类的构造函数创建这个m_mImpl对象,在析构函数释放该对象。

Object::Object()
{
	m_pImpl = new Impl();
}

Object::~Object()
{
	delete m_pImpl;
}

对于之前的直接引用成员变量,现在可以使用m_pImpl->操作来引用了。

定义成内部类

在实际开发中,由于Impl类是Object类的辅助类,所以可以将Impl类定义成Object的内部类,如下:

class Object
{
public:
	Object();
	~Object();

private:
	class Impl;
	Impl* m_pImpl;
};

然后在Object.cpp中定义Impl的实现

class Object::Impl
{
public:
	Impl()
	{
		// 可以做一些初始化工作
	}
	~Impl()
	{
		// 可以做一些清理工作
	}
public:
	char a;
	short b;
	int	c;
	long d;
	long long e;
	float f;
	double g;
};

Object::Object()
{
	m_pImpl = new Impl();
}

Object::~Object()
{
	delete m_pImpl;
}

现在Object这个类除了保留对外的接口,其内部实现用到的变量和方法基本对使用者不可见了。C++中对类的这种封装方法称为pimpl惯用法,即Ponter to Implementation.

使用智能指针来管理

C++11标准引入了智能指针对象,我们可以使用std::unique_ptr对象来管理上述用于隐藏具体实现的m_pImpl指针。修改后:

#include<memory>
class Object
{
public:
	Object();
	~Object();

private:
	struct Impl;
	std::unique_ptr<Impl> m_pImpl;
};

class Object::Impl
{
public:
	Impl()
	{
		// 可以做一些初始化工作
	}
	~Impl()
	{
		// 可以做一些清理工作
	}
public:
	char a;
	short b;
	int	c;
	long d;
	long long e;
	float f;
	double g;
};

Object::Object()
{
	// C++11中未提供std::make_unique方法,是C++14提供的
	m_pImpl.reset(new Impl());
}

// C++14及以上
Object::Object()
	: m_pImpl(std::make_unique<Impl>())
{

}

Object::~Object()
{
	// 不需要显式删除了
	//delete m_pImpl;
}

小结

在实际开发中,Impl类的声明和定义可以使用class关键字,也可以使用struct关键字。struct所有的成员变量和方法默认都是public的。

pimpl惯用法的优点:

  1. 核心数据成员被隐藏,不必暴露在头文件中,提高了安全性。
  2. 降低了编译依赖,提高编译速度。
  3. 接口与实现分离,使用pimpl惯用法之后,即使Object或Impl类的实现细节发生改变,对使用者都是透明的,对外的Object类声明却仍然保持不变。
作者:(美)默里 著,王昕 译 出版日期:2004-2-1 出版社:其它 页数:208 ISBN:9787508319124 文件格式:PDF 书籍简介 本书第1版荣获美国“软件开发”杂志评选的1996年图书震撼大奖(Jolt Award),中文版自2000年推出以来,经久不衰,获得了读者的充分肯定和高度评价。 第2版与第1版相比,在章节安排上有以下改变。增加了两章:“对象的创建与使用”和“C++中的C”。前者与“对象导言”实际上是第1版“对象的演化”一 章的彻底重写,增加了近几年面向对象方和编程方的最新研究与实践的丰硕成果;后者的添加使不熟悉C的读者可以直接使用本书。删去了四章:“输入输出流 介绍”、“多重继承”、“异常处理”和“运行时类型识别”,删去的内容均为C++中较复杂的主题,作者将它们连同C++标准完成后增加的一些内容放到本书 的第2卷中,使本书的第1卷内容显得更加集中,可以供不同程度的读者选择阅读。需要强调的是,第2版的改变不仅体现在这些章节的调整上,更多的改变体现在 每一章的字里行间,包括例子的调整和练习的补充。与众不同的精心选材和认真推敲的叙述使得第2版更趋成熟。 本书是C++领域内一本权威的著作,书中的内容、讲授方、例子和练习既适合课堂教学,又适合读者自学。无论是高等院校计算机及相关专业的学生,还是业界的从业人员,以及广大的计算机爱好者,都可从阅读本书中获益。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

_索伦

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值