pImpl技巧:接口与实现分离
【摘要】 最近在实现某个模块加强了对pImpl设计模式的理解,记录分享给大家。
最近在实现某个模块加强了对pImpl设计模式的理解,这里记录下来备忘。
pImpl模式用来将接口与实现分离,更改实现的话只需要重新编译cpp实现,不影响依赖其抽象的模块,也就是著名的桥接模式。
然而在实践中发现有很多类嵌套类,这种也算是pImpl的体现,但是做的不够完美,因为这些嵌套类直接定义在头文件中,头文件需要暴露出去,其他模块自然也会看到这些内部嵌套类的定义,影响依赖关系。比如:
// Module.h class Module { public: ... private: class InternalModule { // Module部分实现委托到InternalModule内部类 ... } m_module; };
这个模式核心所在是在头文件通过前向声明class Impl,并通过指针指向实例,然后在cpp中定义并实现Impl。
// Person.h #include <memory> class Person { public: Person(std::string name); // (1) ~Person(); // (2) void Dosomething(); ... private: struct Impl; // (3) std::unique_ptr<Impl> pImpl; // (4) }; // Person.cpp #include "Person.h" class Person::Impl { // impl定义与实现 public: Impl(std::string name): name(name) { } void Dosomething() { // ... } private: std::string name; }; void Person::Dosomething() { return pImpl->Dosomething(); } // 构造、析构函数必须放在实现cpp里,避免inline constructor/destructor导致的incomplete type `Impl'问题 Person::Person(std::string name): pImpl(new Impl{name}) // 编程规范问题,可以放到Init()函数中初始化 { } Person::~Person() = default;
需要注意几个点,由于采用std::unqiue_ptr托管pImpl,而std::unqiue_ptr的声明如下:
template <typename _Tp, typename _Dp = default_delete<_Tp>> class unique_ptr;
其中default_delete模板实例化需要看到Impl的定义,而其定义在cpp中,导致构造、析构函数必须得放到cpp中:
(1) 构造函数需要在头文件中声明,cpp中实现,而初始化pImpl可以放到Init函数中
(2) 析构函数同上
(3) 在类内前向声明Impl,避免暴露实现出去
(4) 使用std::unique_ptr托管pImpl。
作者:netcan
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)