Pimpl Idiom
Normally a class is written like
// Foo.h
#include <string>
#include <vector>
class Foo
{
public:
void greet();
private:
std::string name;
std::vector<int> data;
};But now, every .cpp file that includes Foo.h must now also include <string> and <vector>.
If you later change Foo’s private members (say replace std::vector with std::deque), all those .cpp files need recompiling, even though those files only use Foo’s public API.
This is the problem Pimpl idiom seeks to fix.
The idea:
- Keep the class interface (header) stable and minimal.
- Move all data and private functions inside a hidden “implementation” struct that lives in the
.cppfile. - The main class holds only a pointer (
pImpl) to that struct.
// Foo.h
class Foo
{
public:
Foo();
~Foo();
void greet();
private:
struct Impl; // Forward declaration only
Impl* pImpl; // Pointer to implementation
};// Foo.cpp
#include "Foo.h"
#include <string>
#include <iostream>
struct Foo::Impl
{
std::string name = "Ethan";
void greetImpl()
{
std::cout << "Hello, " << name << "!" << std::endl;
}
};
Foo::Foo() : pImpl(new Impl) {}
Foo::~Foo() { delete pImpl; }
void Foo::greet() { pImpl->greetImpl(); }Now, anyone including Foo.h doesn’t need to know about <string> or <iostream>. They just see class Foo { … };.
Why Use Pimpl?
Main reasons:
- Encapsulation at compile-time
Your private members are truly private, even the compiler outside your .cpp doesn’t know them.
- Faster compile times
Changing private data types doesn’t force recompilation of other files.
- Binary compatibility (ABI stability)
If you ship a library (say libFoo.so), changing private details doesn’t break programs that link to it.
- Cleaner headers
Your .h files include only what’s truly needed for the interface, not implementation headers.
Downsides
- Slight runtime cost (one extra pointer indirection).
- More boilerplate (constructors, forwarding functions).
- Not always worth it for small, local projects, but very valuable in libraries or large codebases.