C++学习笔记(十一)——PIMPL设计模式

C++学习笔记(十一)——PIMPL设计模式

本篇解决的问是:

  • 什么是PIMPL设计模式;
  • PIMPL设计模式好与坏;
  • 代码示例实现PIMPL设计模式;

什么是PIMPL设计模式

PIMPL设计模式是Pointer to implement(指针实现)的缩写。其设计特点可以解释为如下3点:
1、头文件只做接口声明;
2、用另外一个.cc文件实现接口;
3、调用接口的文件直接包含头文件就可调用相关的接口;

PIMPL设计模式的利弊

将接口声明与实现分开的设计其好处有:

可以实现敏感数据的隐藏

若不愿意让别人看到类内的私有成员变量时,便可以通过PIMPL设计模式来实现。实例代码如下(代码11-1):

/// file@		Student.h
class Student
{
public:
	Student();
	{...}
	Student(const char * name, int num)
	{...}
	void putName(const char * name)
	{...}
	void putNum(int num)
	{...}
private:
	char * _name;
	int num;	
};

可以看到我们的实现暴露了private成员变量。可以通过PIMPL实现对其隐藏。代码示例如下(代码11-2):

 ///
 /// @file    pimpl_test1.h
 /// @author  XuHuanhuan(1982299154@qq.com)
 /// @date    2019-02-23 15:06:04
 ///
 
#include <iostream>
using std::cout;
using std::endl;
class Student
{
	public:
		Student();
		Student(const char * name, const unsigned num);
		void putName(const char * name);
		void putNum(const unsigned num);
		void print();
	private:
		class Secret;
		Secret * _psecrt;
};

 ///
 /// @file    pimpl_test1.cc
 /// @date    2019-02-23 15:11:11
 ///
 
#include "pimpl_test1.h"
#include <string.h>

#include <iostream>
using std::cout;
using std::endl;

class Student::Secret
{
	public:
		char * _pname;
		unsigned int _num;
		Secret()
		{}
		Secret(const char * pname, const unsigned int num)
			:_pname(new char[strlen(pname)+1]())
			 ,_num(num)
		{
			strcpy(_pname, pname);
		}
};

Student::Student()
{
	_psecrt = new Student::Secret();
}

Student::Student(const char * name, const unsigned num)
{
	_psecrt = new Student::Secret(name,num);
}

void Student::putName(const char * name)
{
	_psecrt->_pname = new char[strlen(name)+1]();
	strcpy(_psecrt->_pname,name);
}

void Student::putNum(const unsigned num)
{
	_psecrt->_num = num;
}

void Student::print()
{
	cout << _psecrt->_pname << endl;
	cout << _psecrt->_num << endl;
}

对比(代码11-1)与(代码11-2)的区别可以看出,其区别在于,使用PIMPL的(代码11-2)的私有成员不再是一个确定类型的成员了,而是一个类指针。这样的好处在于屏蔽了具体的私有对象信息,而只是留下了用户需要使用的接口。

节省编译时间

在C++中有头文件(.h)和实现文件(.cpp),一旦头文件发生变化,不管多小的变化,所有引用它的文件都必须重新编译。对于一个很大的项目,C++一次编译可能就会耗费大量的时间,如果代码需要频繁改动,那真的是不能忍。若 利用 PIMPL 将头文件的接口封装到一个实现类中单独编译,就可以减少头文件对编译的依赖,起到减少编译时间的效果。

屏蔽接口具体,防止别人盗取代码

从(代码11-2)可以看出,头文件pimpl_test.h的接口具体实现全部由pimpl_test.cc完成的。所以,若使用方需要使用该接口,则只需要将pimpl_test.h和由pimpl_test.cc编译成pimpl_test.o文件交给使用方即可。而使用方只能看到pimpl_test.h的代码却没有办法看到各个接口的具体实现。从而实现了保护知识产权的作用。

内存开销增加,间接指针多

使用 PIMPL 需要在堆空间上分配和释放内存,内存开销增加,同时也需要更多的间接指针跳转,因此有一些副作用。

代码示例实现PIMPL设计模式

(代码11-2)所示


版权声明:本文为weixin_39828926原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。