1

I'm trying to learn how to use the PIMPL idiom because it reduces compilation dependencies, which I've heard is recommended. So I have code that essentially looks like this.

Foo.h

class Foo
{
public:
    Foo();
private:
    class FooImpl;
    std::unique_ptr<FooImpl> impl;
}

Foo.cpp

Foo::Foo():
impl(new FooImpl)
{
}

class Foo::FooImpl
{
public:
    FooImpl();
}

But now I want to define FooImpl::FooImpl() in a seperate .cpp file like I did with Foo::Foo(), but how would I go about doing that?

EDIT: I've moved things around to get the code below, but now initializing impl gives me an incomplete type compile error.

Foo.h

class Foo
{
public:
    Foo();
private:
    class FooImpl;
    std::unique_ptr<FooImpl> impl;
}

Foo.cpp

#include "Foo.h"

Foo::Foo():
impl(new FooImpl)
{
}

FooImpl.cpp

#include "Foo.h"

class Foo::FooImpl
{
public:
    FooImpl();
}
rcplusplus
  • 2,767
  • 5
  • 29
  • 43
  • 1
    did you try writing `FooImpl.h` (which must include `Foo.h`) and `FooImpl.cpp`, and include `FooImpl.h` in `FooImpl.cpp`? The idea with PIMPL is for the clients not having to recompile `Foo.cpp` when the implementation `FooImpl.cpp` is being changed. – vsoftco Feb 13 '15 at 01:24
  • see an example here: https://msdn.microsoft.com/en-us/library/hh438477.aspx – vsoftco Feb 13 '15 at 01:34
  • @vsoftco that's how my code looks though. it reduces the compile time dependencies for a file, such as main.cpp, that includes Foo.h. But In that example and in my code the definition for `FooImpl` is constrained to Foo.cpp and I want to move it to FooImpl.cpp – rcplusplus Feb 13 '15 at 01:47
  • @TonyD, I meant clients using `Foo.cpp` not having to recompile (themselves), wish I can edit my comment :) – vsoftco Feb 13 '15 at 01:49
  • @rcplus *"that's how my code looks though"* / *"in my code the definition for FooImpl is constrained to Foo.cpp and I want to move it to FooImpl.cpp"* - can't both be true... vsoftco suggested you move the implementation of FooImpl into its own FooImpl.cpp - what's stopping you? If you can't work out how to do it, edit your question with an update of your current code. – Tony Delroy Feb 13 '15 at 01:51
  • @rcplusplus that's because in `Foo.cpp`, `FooImpl` must be a complete type, since you are allocating memory for it with `new`. That's why you need a `FooImpl.h`, in which to declare `FooImpl`, then include `FooImpl.h` in `Foo.cpp` – vsoftco Feb 13 '15 at 02:09
  • When you compiling foo.cpp, you must know how big is the class Foo. But you don't know it without knowing how big is Foo::FooImp with only declaration but no definition. That's why the compiler tell you incomplete type. – BigTailWolf Feb 13 '15 at 02:23

3 Answers3

2

But now I want to define FooImpl::FooImpl() in a seperate .cpp

The idea of the pimple idiom is to hide the implementation. Been there done that.

However, if the FooImpl class is contained in the Foo.cpp file (and only in that file), then it is already reasonably well hidden. (Most c++ developers will work hard to avoid including a .cpp file.

Thus, you have already achieved the measure of reduced dependencies that pimple can provide.

Before making more work for yourself, try implementing two or three methods of class Foo, then discover how to you must connect them to FooImpl within the Foo.cpp file before introducing a 3rd file.

2785528
  • 5,438
  • 2
  • 18
  • 20
2

My solution is left your definition of FooImp inside your Foo class.

Have all class members there. Then FooImp.cpp include Foo.h and implement all the non-inline functions.

I worked like this:

Foo.h

class Foo
{
public: // ctor & dtor
    Foo();
    ~Foo();

private: // nested class
    class FooImp
    {
    public:
        FooImp();
        ~FooImp();
    };

private: // member variable
    std::unique_ptr<FooImpl> impl;
};

Foo.cpp

#include "Foo.h"
Foo::Foo()
{
}
Foo::~Foo()
{
}

FooImp.cpp

#include "Foo.h"
Foo::FooImp::FooImp()
{
}
Foo::FooImp::~FooImp()
{
}

It compiles fine.

BigTailWolf
  • 1,028
  • 6
  • 17
0

The operator new must know the size of the object being allocated, so your complete FooImpl class declaration must be available to the CPP file containing Foo's constructor, since it uses "new FooImpl".

rodrigovr
  • 454
  • 2
  • 7