减少编译时间:pointer to implementation(Impl设计模式)

参考:点击打开链接


PIMPL(Private Implementation 或 Pointer to Implementation)是通过一个私有的成员指针,将指针所指向的类的内部实现数据进行隐藏。

1)降低模块的耦合。因为隐藏了类的实现,被隐藏的类相当于原类不可见,对隐藏的类进行修改,不需要重新编译原类。

2)降低编译依赖,提高编译速度。指针的大小为(32位)或8(64位),x.h发生变化,指针大小却不会改变,文件c.h(包含x.h)也不需要重编译。

3)接口与实现分离,提高接口的稳定性。


1. #define的保护
所有头文件都应该使用#define 防止头文件被多重包含(multiple inclusion),命名格式
当是:<PROJECT>_<PATH>_<FILE>_H_
为保证唯一性,头文件的命名应基于其所在项目源代码树的全路径。例如,项目foo 中的头
文件foo/src/bar/baz.h 按如下方式保护:
#ifndef FOO_BAR_BAZ_H_
#define FOO_BAR_BAZ_H_
...

#endif // FOO_BAR_BAZ_H_

2. 头文件依赖
使用前置声明(forward declarations)尽量减少.h 文件中#include 的数量。
当一个头文件被包含的同时也引入了一项新的依赖(dependency),只要该头文件被修改,
代码就要重新编译。如果你的头文件包含了其他头文件,这些头文件的任何改变也将导致那
些包含了你的头文件的代码重新编译。因此,我们宁可尽量少包含头文件,尤其是那些包含
在其他头文件中的。
使用前置声明可以显著减少需要包含的头文件数量。举例说明:头文件中用到类File,但不
需要访问File 的声明,则头文件中只需前置声明class File;无需#include
"file/base/file.h"。
在头文件如何做到使用类Foo 而无需访问类的定义?
1) 将数据成员类型声明为Foo *或Foo &;
2) 参数、返回值类型为Foo 的函数只是声明(但不定义实现);
3) 静态数据成员的类型可以被声明为Foo,因为静态数据成员的定义在类定义之外。
另一方面,如果你的类是Foo 的子类,或者含有类型为Foo 的非静态数据成员,则必须为
之包含头文件。
有时,使用指针成员(pointer members,如果是scoped_ptr 更好)替代对象成员(object
members)的确更有意义。然而,这样的做法会降低代码可读性及执行效率。如果仅仅为
了少包含头文件,还是不要这样替代的好。

当然,.cc 文件无论如何都需要所使用类的定义部分,自然也就会包含若干头文件。
译者注:能依赖声明的就不要依赖定义。


以上是Google中C++编程规范的前两条要求。第一条相信大家都知道。第二条就是我要说的问题了。

这里我用VS2012解释下这个事情。要减少编译的目的就是要减少#include;

那我们先定义这样两个类:

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #pragma once  
  2. class A  
  3. {  
  4. public:  
  5.     A(void);  
  6.     ~A(void);  
  7. };  

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #pragma once  
  2. #include "A.h"  
  3. class B  
  4. {  
  5. public:  
  6.     B(void);  
  7.     ~B(void);  
  8. private:  
  9.     A a;  
  10. };  

可以看到这是很简单的组合类的情况。B类中有个A的对象。下面我们生成一下。


这时候A,B第一次编译成功

接下来我们修改对象A,在对象A中增加一个私有成员i,B不变;

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #pragma once  
  2. class A  
  3. {  
  4. public:  
  5.     A(void);  
  6.     ~A(void);  
  7. private:  
  8.     int i;  
  9. };  

这时候再生成一次,可以看到如下情况



可以看到A编译后。编译器发现B中导入了A.h然后又编译了一次B

在工程量比较小的时候这么做是没关系的。但当你编译一次代码需要1分钟2分钟的时候。我们频繁的修改源码然后编译你会崩溃的是不是?

所以前置声明是一个可以选择的解决方案。

B的代码只要做如下修改,取消导入A.h在B.h中声明class A;

[cpp]  view plain  copy
  在CODE上查看代码片 派生到我的代码片
  1. #pragma once  
  2. class A;  
  3. class B  
  4. {  
  5. public:  
  6.     B(void);  
  7.     ~B(void);  
  8. private  
  9.     A* a;  
  10. };  

我们同样在A没修改之前做一次编译。


同样我们在A中加入私有成员后再编译一次。


可以看到这里只编译了A.cpp文件


  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值