PIMPL (Pointer to Implementation)
Refers to “Pointer to Implementation”, and is mostly used to clean up headers. This pattern helps with:
- Compilation firewall: Changes to implementation don’t require recompiling files that include the header
- Hide implementation details: Keep private members truly private
- Reduce header dependencies: Forward declarations instead of includes
When to use generally whenever you are using external, large header-only libraries. To stop people downstream from depending on such a large header during compilation.
Can also be used to solve circular references. Though, generally the fact that you even ran into a circular dependency issue hints at a bigger design problem.
If you need a complete type from the library, then thats when you gots to put it in the header.
Related: unique_ptr usage | Encapsulation
// ---- Header (would normally live in .hpp) ----
class Impl; // forward declaration of implementation
class Image {
public:
Image();
explicit Image(int w, int h);
~Image(); // out-of-line to see full Impl
void set_pixel(int x, int y, uint8_t v);
uint8_t get_pixel(int x, int y) const;
void info() const;
private:
std::unique_ptr<Impl> p_; // opaque pointer
};
// ---- Implementation (would normally live in .cpp) ----
class Image::Impl {
public:
int w{0}, h{0};
std::vector<uint8_t> data; // flat grayscale
Impl() = default;
Impl(int W, int H) : w(W), h(H), data(static_cast<size_t>(W*H), 0) {}
size_t idx(int x, int y) const { return static_cast<size_t>(y*w + x); }
};
// OR IF ITS AN EXTERNAL LIBRARY, YOU JUST #INCLUDE that library in the .cpp
Image::Image() : p_(std::make_unique<Impl>()) {}
Image::Image(int w, int h) : p_(std::make_unique<Impl>(w,h)) {}
Image::~Image() = default; // needs full Impl in this TU
void Image::set_pixel(int x, int y, uint8_t v) {
if (x<0 || y<0 || x>=p_->w || y>=p_->h) throw std::out_of_range("pixel");
p_->data[p_->idx(x,y)] = v;
}
uint8_t Image::get_pixel(int x, int y) const {
if (x<0 || y<0 || x>=p_->w || y>=p_->h) throw std::out_of_range("pixel");
return p_->data[p_->idx(x,y)];
}
void Image::info() const { std::cout << "Image " << p_->w << "x" << p_->h << "\n"; }
