Search code examples
c++pimpl-idiom

PIMPL idiom VS forward declaration


I have read a bit about the PIMPL idiom and was wondering - is it any different to forward declaring the dependent type(s)?

If so:

  • When will I prefer using that over a forward declaration?
  • Do these two versions differ in their compilation time?
  • Is one of them more scalable than the other?

Specifically consider a class Foo that is dependent on Bar (should have a member of type Bar).

Foo.h with forward declaration:

class Bar;

class Foo
{
public:
    Foo();

private:
    Bar* _bar;
};

Foo.h with PIMPL:

class Foo
{
    public:
        Foo();

    private:
        /* FooImpl is an incomplete type at this point.
         * Implemented in cpp file and has a member of type Bar.
         */
        class FooImpl;  

        FooImpl* _fooImpl;
}

Please ignore the raw pointer usage - I was just trying to make a point.


Solution

  • I have read a bit about the PIMPL idiom and was wondering - is it any different to forward declaring the dependent type(s)?

    Yes, they are different. The PIMPL idiom (it has several names) is specifically about hiding the implementation detail from the client code. This could be done for a number of reasons, including (but not limited to);

    • isolating the rebuild when class details change (they are hidden)
    • minimising required or conflicting header inclusions
    • a general build time reduction
    • minimal export requirements (although abstract classes could be used for this purpose as well)
    • easier control over implementation detail that varies over multiple targets or platforms

    In essence, the PIMPL offers a technique to "hide" the implementation from the client code - whenever that may be needed.

    When will I prefer using [PIMPL] over forward declaration?

    This is really about intent - your code is about abstractions - take care of those abstractions, nuture them and protect them, they will serve you well.

    The question becomes - which one better represents your intent? I would venture to say that the FooImpl is better, I sense your intent is to hide the implementation of the class from the client and this implementation better represents that intent (since FooImpl is not accessible to the client).

    If your intent to is to use Bar elsewhere in the code, outside of the class Foo, then that implementation is better because that is the intent and that implementation allows you to do that.

    Do these two versions differ in their compilation time?

    I doubt that. The implementation of Bar and FooImpl are not visible outside the translation unit they are defined in.

    Is one of them more scalable than the other?

    Not really, no. In some generic sense, the clearer code is, the easier people are able to scale it.