(C++) Pimpl
July 25, 2018 · View on GitHub
Pimpl is an abbreviation of 'pointer to implementation'.
The idea of the Pimpl idiom is to give a class (for example 'Lizard') an opaque (smart) pointer to the actual implementation (for example 'LizardImpl'). The opaque (smart) pointer enables it to do a forward declaration of the implementation class only, without the compiler needing to know the actual type. This shortens build times [1]. All the public member functions of the Pimpl class will (often) call the member functions of the implementation class with the same name.
The advantages of using the Pimpl idiom are:
- Shorten build times [1]
- Remove visibility of private member functions [1]
- Improved error handling and safety [1]
The disadvantage of using the Pimpl idiom is the cost of an extra level of indirection, so Pimpl judiciously [1].
Examples
Most lizards remain having the same gender for all their live. Therefore, it is a good idea to make a lizard's gender a const member variable. Problem is, that this makes a lizard class uncopyable. In this example I solve this by making a Lizard contain an opaque pointer to LizardImpl, where a LizardImpl does have a constant gender. Because I want to be able to do a shallow copy on Lizards, I use a boost::shared_ptr. Also note that the code is very similar to a Strategy design pattern.
lizard.h
#ifndef CPP_PIMPL_LIZARD_H
#define CPP_PIMPL_LIZARD_H
enum class Gender { male, female };
#include <memory>
class Lizard
{
public:
Lizard(const Gender gender);
~Lizard();
Gender GetGender() const noexcept;
private:
struct LizardImpl;
std::shared_ptr<LizardImpl> mPimpl;
};
#endif // CPP_PIMPL_LIZARD_H
lizard.cpp
#include "CppPimplLizard.h"
struct Lizard::LizardImpl
{
LizardImpl(const Gender gender);
const Gender mGender;
};
Lizard::Lizard(const Gender gender)
: mPimpl(std::make_shared<LizardImpl>(gender))
{
}
Lizard::~Lizard()
{
//Need destructor definition in implementation file
}
Gender Lizard::GetGender() const noexcept
{
return mPimpl->mGender;
}
Lizard::LizardImpl::LizardImpl(const Gender gender) : mGender(gender)
{
}
References
- [1] Herb Sutter, Andrei Alexandrescu. C++ coding standards: 101 rules, guidelines, and best practices. ISBN: 0-32-111358-6. Item 43: 'Pimpl judiciously'.