C++编程技巧之Pimpl手法

一、Pimpl是什么

Pimpl全称是point to implementation,译为指向实现的指针;是一种c++程序技巧。
其具有如下基本形式:

class widget {
    // 其它部分
private:
    struct impl;        // 前置申明一种变量类型
    impl* pimpl_;       // 定义该类型的指针或引用,用这个pimpl_来隐藏类widget的一些实现细节
};

二、为什么需要Pimpl技术

我们知道,在C/C++中,声明变量是不占用内存的,只有定义变量时,编译器才会为相应的变量分配对应的内存;对于一个C++的类class来说,也是如此。当在类内部定义成员变量时,会影响整个类的内存大小等相关因素;因此,若修改了类中的相关定义实现,即使该实现是private成员这是或者private函数,那么包含这个类的所有用户代码都会被重新编译;因为这些代码依赖于当前类的实现细节。
因此,为了减小编译时的依赖,就可以运用这种Pimpl技术;从其基本的定义形式就可以看出,其大小固定为一个指针大小,而指针所指对象的变化并不影响使用该指针的类的大小,这样一来,用这个impl指针来包裹类widget中容易变动的实现细节,在更改impl对象时,并不影响外部用户代码的编译;其可以带来两个好处:

  • 第一,打破编译依赖,可以使整个系统代码编译速度更快;
  • 第二,其隐藏了内部实现细节的同时,也提高了代码修改的灵活度。

三、怎么使用Pimpl技术

为了使用Pimpl技术,其基本的使用形式如下:

// in header file,即相应的.h头文件
class widget {
public:
    widget();
    ~widget();
private:
    class impl;
    unique_ptr<impl> pimpl;
};
 
// in implementation file,即相应的.cpp/.cxx等文件
class widget::impl {
    // :::
};
 
widget::widget() : pimpl{ new impl{ /*...*/ } } { }
widget::~widget() { } 

其使用细节准则如下:

  • (1)使用std::unique_ptr来管理相应的pimpl指针,这是为了更好的内存管理,避免未翻放相应内存;更详细的原理,可以查阅《Effective C++》第三版的条款13项,以对象管理资源的理念;
  • (2)在.cpp文件中定义实现widget::impl类,以达到隐藏实现细节和减少编译依赖的目的;
  • (3)在.cpp文件中,要显式定义widget::widget和widget::~widget函数,避免编译器默认生成;同样的,对于拷贝构造和赋值构造,若不想被使用,应该申明为私有;若需要被使用,也要显式定义。
  • (4)将widget中所有私有的非虚成员放入impl中去定义和实现;这也是符合OOP编程思想的理念;在OOP编程中,public成员,是为了给外部代码使用;protect和virtual成员是为了给子类继承和修改;而其它私有非虚成员,则是类的实现细节,不影响对外暴露;
  • (5)若impl类中需要访问widget的public成员,则将widget对象作为impl的成员函数的参数,进行传递;一般采用widget指针或者widget引用参数;

四、优缺点总结

优点:

  • 解除了接口和实现之间的偶合,隐藏了实现细节;
  • 减少了编译依赖性,提高编译速度;
  • 更高修改实现的灵活度,而不用考虑外部用户代码。

缺点:

  • widget的public成员函数需要通过impl指针,进一步访问对象数据,添加了一层间接性;
  • 每一个widget对象,相比于最原始实现,至少多消耗一个impl指针大小的内存;
  • widget对象必须初始化impl指针成员,动态分配impl对象;因此,也增加了动态内存分配内存(及后续释放内存)的额外开销;

参数文献:
https://en.cppreference.com/w/cpp/language/pimpl PImpl说明
https://herbsutter.com/gotw/_100/ Compilation Firewalls;
《Effective C++》第三版,条款13,条款31等;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值