The Pimpl Idiom
Thameera Senanayaka
Allion Technologies
aka Opaque Pointer or Cheshire Cat
A look at ABI
- ABI - Application Binary Interface
- Interface between two program modules, at the level of machine code
ABI covers:
- The sizes, alignment, layout of data types
- How fn arguments are passed, etc
- C++ name mangling
- etc
The header file defines ABI
- A change to a header file breaks ABI
- Recompile!
Caveat
- Even adding/deleting a private member can break ABI just as public members/functions.
Also
- Exposes implementation details to third parties
How to design a class which is as binary compatible as possible?
And as private as possible.
Pimpl Idiom
- Pointer to the Implementation
- Keep all details of implementation outside header file
- Implementation details go in a private class
- Keep a pointer to the private class in header
- Class forwarding
Basically, the API class contains:
- API methods
- A private pointer to the implementation
Old way
class Image
{
public:
Image();
virtual ~Image();
int crop();
int setBrightness(int x);
private:
void resize(int x, int y);
unsigned char* imgData;
unsigned int w, h;
};
Pimpl Idiom - Header
class Image
{
public:
Image();
virtual ~Image();
int crop();
int setBrightness(int x);
private:
class Impl;
Impl* _impl;
};
Pimpl Idiom - Implementation
class Image::Impl
{
public:
int crop() { /* */ }
int setBrightness() { /* */ }
private:
void resize(int x, int y) { /* */ }
void* imageData;
unsigned int w, h;
};
Image::Image : _impl(new Impl()) {
}
Image::~Image {
if (_impl)
delete _impl;
}
int Image::crop() {
return _impl->crop();
}
int Image::setBrightness(int x) {
return _impl->setBrightness(x);
}
Adding pointer semantics
class Image
{
/* ... */
bool operator==(Image const& that) const { return _impl == that._impl; }
bool operator!=(Image const& that) const { return !operator==(that); }
operator bool() const { return impl_; }
/* ... */
};
Other operators
class Image
{
public:
/* ... */
Image(const Image&); // copy ctor
Image& operator=(const Image&); // copy assignment operator
/* ... */
};
C++11 goodness
- Use a std::unique_ptr for _impl
- No need to destroy manually
class Image
{
public:
/* ... */
private:
class Impl;
std::unique_ptr<Impl> _impl;
};
Pros of Pimpl
- Really hide the private parts
- ABI isn't broken unless public API is changed
- Lesser dependencies for the header file (why?)
- Faster compilation times (why?)
Cons of Pimpl
- Overhead of a pointer call
- Extra heap allocation
Thank you!
The Pimpl Idiom
By Thameera
The Pimpl Idiom
An explanation of the Pimpl Idiom as used in C++
- 1,232