需求
cpp impl 是什么?
解决
impl 解决的问题
- 依赖太多,包含头文件过多,一个头文件修改,一堆源文件都需要重新编译,导致的编译时间过长。
- 库文件,不喜欢在头文件中暴露太多的内部成员变量等信息给使用着。
简单 pimpl
// 使用Pimpl
// 在头文件person.hpp中
#include <memory>
class Person {
public:
Person();
private:
// Person类的实现细节放置在该前向声明的实现类中。
struct Impl;
// 指向实现类Impl的私有指针
std::unique_ptr<Impl> pimpl_;
};
// 在源文件person.cpp中
#include "person.hpp"
#include "basic_info.hpp"
#include <string>
#include <memory>
struct Person::Impl {
std::string name;
std::string id;
BasicInfo basic_info;
};
Person::Person() : pimpl_(std::make_unique<Impl>()) {}
具体的成员变量放到 cpp 文件中,编译为库后,有以下好处:
- 就算需要修改包含的成员变量,也不需要修改头文件,那么编译的时候,只会编译这个 cpp 文件,其他依赖这个头文件的都不需要重新编译。
- 使用者并不能从头文件中发现成员变量的细节。
pimpl 更多细节
pimpl 在使用的时候,还会碰到很多需要注意的地方:
- 析构函数的实现需要完整的类型
- 移动赋值需要完整类型
- 移动构造需要完整类型
- 拷贝构造和拷贝赋值都需要完整类型
所以上面这些都需要放在 cpp 中实现。
#ifndef WEIGHT_H
#define WEIGHT_H
#include <memory>
class Weight
{
public:
Weight();
~Weight();
Weight(Weight&& rhs);
Weight& operator=(Weight&& rhs);
private:
struct Impl;
std::unique_ptr<Impl> m_impl;
};
#endif // WEIGHT_H
#include "Weight.h"
#include <vector>
#include <string>
struct Weight::Impl {
std::string name;
std::vector<double> data;
};
Weight::Weight()
: m_impl(new Impl())
{
}
Weight::~Weight() = default;
Weight::Weight(Weight&& rhs) = default;
Weight& Weight::operator=(Weight&& rhs) = default;
Weight& Weight::operator=(const Weight& rhs) {
if (this != &rhs) {
*m_impl = *rhs.m_impl;
}
return *this;
}