当前位置: 首页 > 工具软件 > Pimp3 > 使用案例 >

pImp机制--隐藏实现减小头文件依赖

笪烨
2023-12-01
pImp是private implemention的缩写。在C++中,当需要引用其他头文件中定义的类、函数、变量时,需要在应用前将需要的头文件包含到当前的文件中。如,
   
[cpp]  view plain  copy
  1. //头文件"A.h"  
  2.     #pragma once  
  3.     class A  
  4.     {  
  5.         ...  
  6.     }  

[cpp]  view plain  copy
  1. //头文件"B.h"  
  2. #pragma once  
  3. #include "A.h"  
  4. class B  
  5. {  
  6.     ...  
  7.     A a;  
  8. }  

在编译头文件"B.h"时,编译器首先需要变以头文件"A.h",因为类B依赖类A,只有知道类A的构成之后,编译器才能确定类B对象的结构,才能够为B对象分配内存。假如类A的头文件发生了变化,那在编译时,类B也必须进行重新编译。而进一步假设类B也 以同样的方式被类C引用,类C又被类D引用...,那头文件"A.h"的改变会导致所有类的重新编译,这样会大大增加增加编译时间。对于一个大型项目而言,有时是不可接受的。因此在实际编程中,需要减小头文件之间的依赖关系,这也就是这里的pImp机制。
此处,我们将"B.h"修改为如下:
   
[cpp]  view plain  copy
  1. //头文件"B.h"  
  2. #pragma once  
  3. class A;  
  4. class B  
  5. {  
  6.     ...  
  7.     A * a;    //此处只作示意用,实际编程中应该尽可能的使用智能指针替代  
  8. }  

这样一来,编译器就无需知道类A的具体结构即可确定类B对象的内存结构了,因为此处成员变量"a"只占是一个指针,在32位系统上只占4个字节,它的大小与类A没有关系。所以当头文件"A.h"改变时,便只需要对"A.h"进行重新编译即可,而"B.h"无需重新编译。
除了这种头文件之间的pImp,在单个类中也可以使用这种思想,例如,假设我们有如下类:
[cpp]  view plain  copy
  1. //头文件"A.h"  
  2. #pragma once  
  3. class A  
  4. {  
  5.     ...  
  6.     private:  
  7.         class Inner      
  8.         {  
  9.                 ...  
  10.         };  
  11.         Inner innerMember;  
  12. };  

以上类A中,有一个内部类Inner,假如过了一段时间,由于新的需求,需要对Inner类进行修改,这便会导致所有依赖头文件"A.h"的头文件全部需要重新编译。为了避免这种依赖,这里同样可以使用pImp机制,在头文件中声明类Inner,在cpp文件中对Inner类进行定义,构造函数中初始化成员指针innerMember:
 
[cpp]  view plain  copy
  1. //头文件"A.h"  
  2. #pragma once  
  3. class A  
  4. {  
  5.    class Inner;      
  6.     ...  
  7.     private:  
  8.         Inner * innerMember; //仅仅示意用,实际情况应该使用智能指针  
  9. };  

[cpp]  view plain  copy
  1. //实现文件"A.cpp"  
  2. class A::Inner  
  3. {  
  4.     ...  
  5. }  
  6.   
  7. A::A()  
  8. {  
  9.     innerMember = new Inner;  
  10. }  

当然,采用pImp机制会带来额外的开销,因为这种方式的成员需要利用new来动态分配内存。另外,也会容易造成内存泄露,而为了避免内存泄露,应该采用 RAII机制,利用智能指针替代原始指针。    

 类似资料: