PIMPL(二)
上一篇文档,PIMPL(一)
1 如何使用PIMPL
有多种方式实现PIMPL,这里按照《Effective C++》中介绍的方式。
1.1 基本步骤
假设原有Person如下:
Person.h
struct Person
{
public:
Person(const int _age);
void print(); private:
int age;
};
Person.cc
Person::Person(const int _age)
: age(_age)
{} void
Person::print()
{
std::cout << "Person::print::age=" << age << std::endl;
}
1.1.1 将Person改名为PersonImpl
PersonImpl.h
struct PersonImpl
{
public:
PersonImpl(const int _age);
void print(); private:
int age;
};
PersonImpl.cc
PersonImpl::PersonImpl(const int _age)
: age(_age)
{} void
PersonImpl::print()
{
std::cout << "PersonImpl::print::age=" << age << std::endl;
}
1.1.2 抽象public和protected方法
将PersonImpl中的public和protected方法成Person。Person中的方法实际调用的是PersonImpl中对应的方法,Person的定义中需要使用PersonImpl,在Person.h文件中绝对不能#include “PersonImpl.h”,这样就是做无用功了。
- 为什么不能将PersonImpl的对象作为Person的成员变量?
因为Person类的定义中需要知道该类的大小,如果直接使用PersonImpl的对象,那么就必须知道PersonImpl的定义,而我们恰恰希望在Person的定义中隐藏PersonImpl的定义。这时候,指针就大显神通了。因为指针的大小只与操作系统的位数有关(32位的机器都占4个字节,64位的机器都占8个字节),所以我们可以使用指针指向PersonImpl,从而只需要前置声明就可以了。这就是暗度陈仓吧。
Person.h
struct PersonImpl; // 前置声明,PIMPL的关键 struct Person
{
public:
Person(const int _age);
void print(); private:
std::shared_ptr<PersonImpl> pImpl; // 指针,暗度陈仓
};
Person.cc
Person::Person(const int _age)
: pImpl(new PersonImpl(_age))
{} void
Person::print()
{
pImpl->print();
}
1.1.3 使用Person
在其它地方我们就可以使用Person了,例如:
int main()
{
Person p();
p.print(); return ;
}
1.1.4 示例源码下载
2 优缺点
2.1 优点
- 改变类的私有成员无需重新编译依赖它的文件,所以整个工程重新编译的速度会快很多。
- 头文件中采用声明式,因此编译时间会快很多。
- 接口与实现的分离,更有利于单元测试。
2.2 缺点
- 实现者需要做更多的工作。
- 代码会变得不易理解。
- 运行时动态的获取要执行的方法,性能降低。
- 需要注意定义拷贝构造换函数或将其禁用。
3 总结
如《Effective C++》中所说:
- 如果使用object reference或object pointers可以完成任务,就不要使用objects。
- 尽量以class声明式替换class定义式。
4 参考
- 《effective C++》 条款31:将文件间的编译关系降至最低
- PIMPL Idiom: http://c2.com/cgi/wiki?PimplIdiom
PIMPL(二)的更多相关文章
- pImpl
之前看代码,一直对pIml这个用法一知半解,参考这里 的一篇文章后有所收获. 总结一下,pIml的好处如下: 第一,引入更多的头文件降低编译速度.而且这个声明当然写在一个头文件里,而头文件,是不能预编 ...
- 实现私有化(Pimpl) --- QT常见的设计模式
转载自:http://blog.sina.com.cn/s/blog_667102dd0100wxbi.html 一.遇到的问题 1.隐藏实现 我们在给客户端提供接口的时候只希望能暴露它的接口,而隐藏 ...
- 类声明、类作用域、前向声明、this指针、嵌套类、PIMPL 技法 等
一.类声明 //类是一种用户自定义类型,声明形式: class 类名称 { public: 公有成员(外部接口) private: 私有 ...
- Pimpl Idiom /handle body idiom
在读<Effective C++>和项目源代码时,看到pImpl Idiom.它可以用来降低文件间的编译依赖关系,通过把一个Class分成两个Class,一个只提供接口,另一个负责实现该接 ...
- Qt源码解析之-从PIMPL机制到d指针
一.PIMPL机制 PIMPL ,即Private Implementation,作用是,实现 私有化,力图使得头文件对改变不透明,以达到解耦的目的 pimpl 用法背后的思想是把客户与所有关于类的私 ...
- C++学习笔记之pimpl用法详解
原文链接:https://www.jb51.net/article/122557.htm 在编写稳定代码是,管理好代码间的依赖性是不可缺少的一个环节.特别是库文件的编写中,减少代码间的依赖性可以提供一 ...
- ApacheCN C/C++ 译文集(二) 20211204 更新
编写高效程序的艺术 零.序言 第一部分:性能基础 一.性能和并发性介绍 二.性能测量 三.CPU 架构.资源和性能 四.内存架构和性能 五.线程.内存和并发 第二部分:高级并发 六.并发和性能 七.并 ...
- 【小程序分享篇 二 】web在线踢人小程序,维持用户只能在一个台电脑持登录状态
最近离职了, 突然记起来还一个小功能没做, 想想也挺简单,留下代码和思路给同事做个参考. 换工作心里挺忐忑, 对未来也充满了憧憬与担忧.(虽然已是老人, 换了N次工作了,但每次心里都和忐忑). 写写代 ...
- 前端开发中SEO的十二条总结
一. 合理使用title, description, keywords二. 合理使用h1 - h6, h1标签的权重很高, 注意使用频率三. 列表代码使用ul, 重要文字使用strong标签四. 图片 ...
随机推荐
- javah生成jni头文件时报错 Error: cannot access android.support...
javah生成jni头文件时报错: Error: cannot access android.support.v7.app.AppCompatActivity class file for andro ...
- LeetCode 33 Search in Rotated Sorted Array(循环有序数组中进行查找操作)
题目链接 :https://leetcode.com/problems/search-in-rotated-sorted-array/?tab=Description Problem :当前的数组 ...
- PtH(hash传递攻击)原理探秘
背景知识 Windows 横向渗透的两种方式 1.hash传递攻击,通过传递NTLM-Hash,登录机器,简称PtH: 2.ticket传递攻击,通过传递kerberos的ticket,登录机器,简称 ...
- import 与 from…import 的区别
首先你要了解 import 与 from…import 的区别. import 模块:导入一个模块:注:相当于导入的是一个文件夹,是个相对路径. from…import:导入了一个模块中的一个函数:注 ...
- 【咸鱼教程】Base64
教程目录1 Base64简介2 使用Base643 Demo下载 1 Base64简介百度百科:Base64是网络上最常见的用于传输8Bit字节代码的编码方式之一,大家可以查看RFC2045-RFC2 ...
- “找女神要QQ号码”——java篇
题目就是这样的: 给了一串数字(不是QQ号码),根据下面规则可以找出QQ号码: 首先删除第一个数,紧接着将第二个数放到这串数字的末尾,再将第三个数删除,并将第四个数放到这串数字的末尾...... 如此 ...
- 涨知识,涨知识 :ThinkPHP框架下Where条件查询Mysql数据库某字段是否为空
代码虐我千百遍,我对代码如初恋~ 问题: 查询某字段app_date数据是否为NULL,正常我们实现的办法是: $map['app_data'] = array('eq','null'); $data ...
- 170810、spring+springmvc+Interceptor+jwt+redis实现sso单点登录
在分布式环境中,如何支持PC.APP(ios.android)等多端的会话共享,这也是所有公司都需要的解决方案,用传统的session方式来解决,我想已经out了,我们是否可以找一个通用的方案,比如用 ...
- 安装和卸载windows服务程序
安装window服务 安装命令:InstallUtil.exe MyServiceLog.exe InstallUtil存在路径为:C:\WINDOWS\Microsoft.NET\Framework ...
- easyui treegrid idField 所在属性中值有花括号(如Guid)当有鼠标事件时会报错,行记录一下
easyui treegrid idField 所在属性中值有花括号(如Guid)当有鼠标事件时会报错,行记录一下