何为 pimpl ?
前言
你是否总因头文件包含冲突而苦恼?
你是否因头文件包含错乱而苦恼?
你是否因封装暴露了数据而苦恼?
你是否因经常改动实现而导致重新编译而苦恼?
在这里, 这些问题都不是问题, 跟随作者, 揭秘pimpl.
正文
先来看一段例子:
有A, B 2个类, 分别由A.h, A.cpp, B.h, B.cpp文件实现.
同时, A类中包含了B类成员, B类中包含了A类成员.
// A.h
#include "B.h"
class A {
private:
B b;
};
// B.h
#include "A.h"
class B {
private:
A a;
};
你是否一眼就看出了问题!
是的, 头文件互相包含了, 那怎么解决此问题?
解决方案?
// A.h
class B;
class A {
public:
A();
~A();
private:
B *pB;
};
// A.cpp
#include "B.h"
A::A(): pB(new B())
{
}
A::~A()
{
delete pB;
}
// B.h
class A;
class B {
public:
B();
~B();
private:
A *pA;
};
// B.cpp
#include "A.h"
B::B(): pA(new A())
{
}
B::~B()
{
delete pA;
}
我们在头文件中互相前置声明, 这种行为是"不要钱"的, 大伙可以尽情的用.
随后在源文件中, 互相包含头文件, 在各自的构造函数中new 出对象, 析构函数中 delete 对象.
仅此而已?
接下来才是pimpl的重度解说.
假设我们的A需要实现成员函数 AmemberFunc.
这个成员函数过程复杂, 可能需要分割成多个小函数.
因此就有了一下清单:
func1();
func2();
...
funcN();
过程中还需要一系列成员变量.
因此就有了一下清单:
type1 var1, var2 ... varN;
type2 var1, var2 ... varN;
...
typeN var1, var2 ... varN;
注意, 你需要的仅仅是使用A的AmemberFunc接口.
其他的任何东西在你眼里都是累赘, 他们并不能让你更清楚实现, 反而扰乱你的思绪.
当你使用一个只有一个接口的对象时, 查看其头文件, 发现一堆的成员清单,
如果你胆子比较大, 或许会去源文件查看清单中的东西到底都在干什么.
这个时候的你已经走向歧途了.
当然, 也可能源文件已经被编译成了库文件, 你的壮志雄心不得已施展.
再次注意, 你需要的仅仅是这个接口, 至于接口的实现... 除非你的目的是把这个接口一探究竟, 否则纯属浪费时间.
废话说了不少, 看看解决方案.
// A.h
class A {
public:
A();
~A();
type memberFunc();
private:
class impl;
impl *pimpl;
};
// A.cpp
#include "B.h"
class A::impl {
type memberFunc()
{
...
}
private:
func1();
func2();
...
funcN();
type1 var1, var2 ... varN;
type2 var1, var2 ... varN;
...
typeN var1, var2 ... varN;
};
A::A(): pimpl(new impl())
{
}
A::~A()
{
delete pimpl;
}
type A::memberFunc()
{
return pimpl->memberFunc();
}
A的内部声明了一个impl类型.
该类实例负责实现A的所有功能.
A只需调用impl相应的函数.
此方法隐藏了所有不需要暴露的细节.
并且避免了头文件的依赖. (因为实现在源文件中, 你可以在里面包含任意头文件不必考虑冲突问题.)
增强了可读性, 用户不会被"细节"扰乱思绪.
尾声
pimpl的功能远不止这些, 你可以在pimpl中抛出异常, 在外层类中捕获异常, 从而让异常完全透明.
还有更多功能, 等着你去发现..
当然, pimpl的缺陷也是显而易见的.
那就是不能内联! 不过谁会在意呢.
何为 pimpl ?的更多相关文章
- pImpl
之前看代码,一直对pIml这个用法一知半解,参考这里 的一篇文章后有所收获. 总结一下,pIml的好处如下: 第一,引入更多的头文件降低编译速度.而且这个声明当然写在一个头文件里,而头文件,是不能预编 ...
- [linux]如何为Virtualbox虚拟硬盘扩容(转载)
前言 这个教程介绍如何为Virtualbox虚拟硬盘扩容,虚拟硬盘分为动态分配大小和固定虚拟硬盘,扩容的方法不一样: 如何为动态分配的Virtualbox虚拟硬盘扩容 如何为固定大小的Virtualb ...
- AngularJS入门心得2——何为双向数据绑定
前言:谁说Test工作比较轻松,最近在熟悉几个case,差点没疯.最近又是断断续续的看我的AngularJS,总觉得自己还是没有入门,可能是自己欠前端的东西太多了,看不了几行代码就有几个常用函数不熟悉 ...
- 何为“精通Java”
何为精通Java?本来Java仅仅是一门语言,但从应用技术的角度来看,精通Java是可以无边无际的.很可能你可以对James说:我精通J2EE.JVM.Java服务器.大数据等等一些和Java相关的应 ...
- 如何为PHP贡献代码
PHP在之前把源代码迁移到了git下管理, 同时也在github(https://github.com/php/php-src)上做了镜像, 这样一来, 就方便了更多的开发者为PHP来贡献代码. 今天 ...
- 如何为 Drupal 7 网站添加悬浮的反馈按钮?
最近有客户咨询我们要怎么为 Drupal 网站添加悬浮按钮,方便访客能够链接到反馈表单页面.很幸运,使用 Feedback Simple 模块可以很容易实现. 在这篇短教程中,我将和大家分享如何添加链 ...
- 如何为Linux安装Go语言
导读 Go 语言又称为 golang, 是由 Google 最初开发的一种开源编程语言,其在设计时就遵循了简单.安全和速度的 3 大原则.Go 语言具有多种调试.测试.分析和代码审查工具,如今 Go ...
- JS基础DOM篇之一:何为DOM?
近日在园子看了一篇文章,一位前端负责人问应聘者何为DOM事件流的三个阶段,我当时一看也是懵圈,于是强迫症复发,遂想要搞清楚它.谁知在查资料的过程中发现有好多关于DOM的概念也是模糊不清,便决定继续延伸 ...
- [021]转 C++ Pimpl机制
出处:http://www.cnblogs.com/gnuhpc/ 1.简介 这个机制是Private Implementation的缩写,我们常常听到诸如“不要改动你的公有接口”这样的建议,所以我们 ...
随机推荐
- dwr消息推送和tomcat集群
网友的提问: 项目中用到了dwr消息推送.而服务端是通过一个http请求后 触发dwr中的推送方法.而单个tomcat中.服务器发送的http请求和用户都在一个tomcat服务器中.这样就能精准推送到 ...
- nodejs触发事件的两种方式
nodejs触发事件的两种方式: 方式之一:通过实例化events.EventEmitter //引入events模块 var events = require('events'); //初始化eve ...
- 物理卷操作命令:pvcreate,pvscan,pvdisplay.卷组操作命令:vgcreate,vgdisplay.
新硬盘创建LVM系统过程. 物理卷操作命令:pvcreate,pvscan,pvdisplay. 卷组操作命令:vgcreate,vgdisplay. 逻辑卷操作命令:lvcreate,lvdispl ...
- Pie(二分)
ime Limit: 1000MS Memory Limit: 65536K Total Submissions: 8930 Accepted: 3235 Special Judge De ...
- 【转】java中byte数组与int类型的转换(两种方式)----不错
原文网址:http://blog.csdn.net/piaojun_pj/article/details/5903009 java中byte数组与int类型的转换,在网络编程中这个算法是最基本的算法, ...
- 转:给C++初学者的50个忠告
转:给C++初学者的50个忠告 1.把C++当成一门新的语言学习(和C没啥关系!真的.): ...
- 使用iScroll和photoswipe写手机浏览图片的插件的几点经验
首先,当我知道我得到一个任务需要写一个在手机上能浏览图片的插件时,我第一想到了iScroll.它的左右滑动,上下滑动的效果在安卓手机上也能让用户有良好的体验,自己写也能方便控制. 我的需求是,插件要能 ...
- getconf 取系统配制 --CPU
cpu 缓存:getconf -a LEVEL1_ICACHE_SIZE LEVEL1_ICACHE_ASSOC LEVEL1_ICACHE_LINESIZE LEVEL1_DCACHE_SIZE L ...
- Linux Top 命令解析 比较详细--转
TOP是一个动态显示过程,即可以通过用户按键来不断刷新当前状态.如果在前台执行该命令,它将独占前台,直到用户终止该程序为止.比较准确的说,top命令提供了实时的对系统处理器的状态监视.它将显示系统中C ...
- JDK5-注解
注解是一个类,一个声明就是一个对象 1. 简单注解 @SuppressWarnings("msg") - 压缩/抑制警告 @Deprecated - 声明过时 @Override ...