C++ 编译期封装-Pimpl技术
Pimpl技术——编译期封装
Pimpl 意思为“具体实现的指针”(Pointer to Implementation),
它通过一个私有的成员指针,将指针所指向的类的内部实现数据进行隐藏,
是隐藏实现,降低耦合性和分离接口实现的一个现代 C++ 技术,并有着“编译防火墙(compilation firewall)”的名头。
Pimpl技术的基本应用
其中利用了C++11的std::unique_ptr来让Impl指针的内存更易受控制。
此外由于声明了析构函数,导致默认的移动构造/赋值函数不能生成,若默认行为符合自己的需求,则需显式声明 = default
(当只在.h里,Impl是个不完整的类型,所以无法在.h类直接 = default,而是在.h声明,在.cpp使= default)
若需要给类提供拷贝性质的函数,需要额外花点心思处理std::unique_ptr(该智能指针不支持拷贝)。
// my_class.h #pragma once #include <memory> class my_class { // ... 所有的公有/保护接口都可以放在这里 ... my_class(); ~my_class(); my_class(my_class&& v); //移动构造 my_class& operator=(my_class&& v); //移动赋值 private: class Impl; std::unique_ptr<Impl> pimpl; };
// my_class.cpp // ...include其它要依赖的头文件... #include "my_class.h" class my_class::Impl { // 在这里定义所有私有变量和方法(换句话说是my_class类的具体实现细节内容) // 现在可以改变实现,而依赖my_class.h的其他类无需重新编译... }; my_class::my_class():pimpl(std::make_unique<Impl>()){ // ...初始化pimpl... } my_class::~my_class() = default; my_class::my_class(my_class&& v) = default; my_class::my_class& operator=(my_class&& v) = default;
代码示例
//View.h文件 #pragma once #include <memory> class View { public: View(); ~View(); View(View&& v); View& operator=(View&& v); void display(); private: class Impl; std::unique_ptr<Impl> pimpl; };
//View.cpp文件 #include <iostream> #include <string> #include "View.h" ///////////////////////////////////////////////////////// //下面是View::Impl的定义,也就是体现了View类的具体实现细节 class View::Impl { std::string name; public: Impl(); void printName(); }; View::Impl::Impl(){ name = "DefaultName"; } void View::Impl::printName(){ std::cout << "this is my name:" << name; } /////////////////////////////////////////////////////////// //下面是View类接口的实现 View::View():pimpl(std::make_unique<Impl>()){ } View::~View() = default; View::View(View&& v) = default; View& View::operator = (View&& v) = default; void View::display(){ pimpl->printName(); }
什么时候使用Pimpl技术?
可以看到Pimpl拥有如下优点:
-
减少依赖项(降低耦合性):其一减少原类不必要的头文件的依赖,加速编译;其二对Impl类进行修改,无需重新编译原类。
-
接口和实现的分离(隐藏了类的实现):私有成员完全可以隐藏在共有接口之外,给用户一个间接明了的使用接口,尤其适合闭源API设计。
- 可使用惰性分配技术:类的某部分实现可以写成按需分配或者实际使用时再分配,从而节省资源。
Pimpl也拥有一些缺点:
-
每个类需要占用小小额外的指针内存。
-
每个类每次访问具体实现时都要多一个间接指针操作的开销,并且再使用、阅读和调试上都可能有所不便。
可以说,在性能/内存要求不敏感(非极端底层)的领域,Pimpl技术可以有相当不错的发挥和作用。
作者:KillerAery
出处:http://www.cnblogs.com/KillerAery/
本文版权归作者和博客园共有,未经作者同意不可擅自转载,否则保留追究法律责任的权利。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了