Why should the "PIMPL" idiom be used?


Question

Backgrounder:

The PIMPL Idiom (Pointer to IMPLementation) is a technique for implementation hiding in which a public class wraps a structure or class that cannot be seen outside the library the public class is part of.

This hides internal implementation details and data from the user of the library.

When implementing this idiom why would you place the public methods on the pimpl class and not the public class since the public classes method implementations would be compiled into the library and the user only has the header file?

To illustrate, this code puts the Purr() implementation on the impl class and wraps it as well.

Why not implement Purr directly on the public class?

// header file:
class Cat {
    private:
        class CatImpl;  // Not defined here
        CatImpl *cat_;  // Handle

    public:
        Cat();            // Constructor
        ~Cat();           // Destructor
        // Other operations...
        Purr();
};


// CPP file:
#include "cat.h"

class Cat::CatImpl {
    Purr();
...     // The actual implementation can be anything
};

Cat::Cat() {
    cat_ = new CatImpl;
}

Cat::~Cat() {
    delete cat_;
}

Cat::Purr(){ cat_->Purr(); }
CatImpl::Purr(){
   printf("purrrrrr");
}
1
127
9/9/2016 7:27:02 AM

Accepted Answer

  • Because you want Purr() to be able to use private members of CatImpl. Cat::Purr() would not be allowed such an access without a friend declaration.
  • Because you then don't mix responsibilities: one class implements, one class forwards.
40
9/12/2013 9:49:04 AM

I think most people refer to this as the Handle Body idiom. See James Coplien's book Advanced C++ Programming Styles and Idioms (Amazon link). It's also known as the Cheshire Cat because of Lewis Caroll's character that fades away until only the grin remains.

The example code should be distributed across two sets of source files. Then only Cat.h is the file that is shipped with the product.

CatImpl.h is included by Cat.cpp and CatImpl.cpp contains the implementation for CatImpl::Purr(). This won't be visible to the public using your product.

Basically the idea is to hide as much as possible of the implementation from prying eyes. This is most useful where you have a commercial product that is shipped as a series of libraries that are accessed via an API that the customer's code is compiled against and linked to.

We did this with the rewrite of IONAs Orbix 3.3 product in 2000.

As mentioned by others, using his technique completely decouples the implementation from the interface of the object. Then you won't have to recompile everything that uses Cat if you just want to change the implementation of Purr().

This technique is used in a methodology called design by contract.


Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon