Pimpl(Pointer to implementation) 是一种减少代码依赖和编译时间的C++编程技巧,其基本思想是将一个外部可见类(visible class)的实现细节(一般是所有私有的非虚成员)放在一个单独的实现类(implementation class)中,而在可见类中通过一个私有指针来间接访问该实现类。
假设我们在某个模块时,需要暴露出去一个person.hpp头文件,并向用户提供Person的功能。
但是Person中还有一些private函数和字段,这些函数和字段我们本意可能是不想被用户知道,因为可能里面有些隐私内容,用户有可能通过这些private方法和字段就能猜到我们的架构及实现。
class Person {
public:
void func1();
private:
void func2();
int age;
int name;
};
因此我们可以把Peson类的实现细节放在Person::Impl中, 而在Person中使用私有的std::unique_ptr来访问Person::Impl。
person.hpp
class Person {
public:
void func1();
private:
class Impl;
std::unique_ptr<Impl> pimpl_;
};
person.cpp
class Person::Impl {
public:
void func1();
private:
void func2();
int age;
int name;
};
Person::Person() {
pimpl_ = new Impl;
}
void Person::func1() {
pimpl_->func1();
}
当然 Impl也可以是 struct, 如
#include <memory>
class Person {
public:
Person();
private:
// Person类的实现细节放置在该前向声明的实现类中。
struct Impl;
// 指向实现类Impl的私有指针
std::unique_ptr<Impl> pimpl_;
};
#include "person.hpp"
#include <string>
#include <memory>
struct Person::Impl {
std::string name;
std::string id;
};
Person::Person() : pimpl_(std::make_unique<Impl>()) {
}
pimpl模式的优点:
- 非常适合隐藏private实现:如果想要在头文件中暴露public接口,但又不想暴露private实现的细节,则可以使用pimpl模式来隐藏细节。
- pimpl模式也被称为编译防火墙,是一种用来减少编译时间的方法。通常来讲,如果头文件里的某些内容变更了,意味着所有引用该头文件的代码都要被重新编译,即使变更的是无法被用户类访问的私有成员。将这部分代码从被引用多次的头文件里移除到只被引用编译一次的源文件中,更改此文件就不会付出太长的编译时间。