Why not choose this design :
// A.hpp
class A
{
public:
void do_something();
};
// A.cpp
#include "A.hpp"
#include <vector>
std::vector<int> impl_database_for_do_something;
static void impl_helper_for_do_something(const std::vector<int>& database){}
void A::do_something(){ impl_helper_for_do_something(impl_database_for_do_something); }
Instead of this one :
// A.hpp
#include <vector>
class A
{
public:
void do_something();
private:
std::vector<int> database_for_do_something_;
void helper_for_do_something(const std::vector<int>& database){}
};
Could I hide implementation details and speed-up compilation with variables and static functions defined in the source file ? If not, what's wrong with this design (besides inheritance) ?
In the first case there is only one instance of impl_database_for_do_something for the entire program. You want one instance of it per instance of A. So the code is not in any sense equivalent.
If you use global vectors to store state as you propose, you will somehow have to make sure that different instances of class A use different parts of the vector (besides the obvious difficulties of doing so, consider how much harder this gets if different threads use different instances of A). This design only makes very much sense if A is a singleton.
Your first design has one vector for all instances of A; the latter has one per instance. Read up on instance variables vs. class variables.
This is not, at all, PIMPL: Pointer to IMPLementation.
You could do it this way:
// A.hpp
#include <boost/shared_ptr.hpp>
class A
{
public:
A();
void foo();
private:
struct Impl;
boost::shared_ptr<Impl> _impl;
};
// A.cpp
#include <vector>
#include "A.hpp"
struct A::Impl {
std::vector<int> _data;
};
A::A(): _impl(new std::vector<int>()) {}
void A::foo() {
_impl->_data.push_back(3);
}
Warning: this code does not deal with proper copying / assignment behavior, it is left as an exercise to the reader.
Related
In my workplace we have this convention: almost every class (with very few exceptions) is implemented with unique_ptrs, raw pointers or references as member variables.
This is because of compilation times: in this way you just need a forward declaration for the class in your header file and you only need to include the file in your cpp. In addition if you change the .h or the .cpp of a class that you are including with unique_ptr you will not need to recompile.
I think that this pattern has at least these downsides:
it forces you to write your own copy constructors and assignment operators and you have to manage each variable individually, if you want to keep the semantic of copying.
the syntax of the code become very cumbersome, for example you will have std::vector<std::unique_ptr<MyClass>> instead of the much more simple std::vector<MyPimplClass>.
the constness of the pointer is not propagated to the pointed object, unless you use std::experimental::propagate_const, which I cannot use.
So it came to my mind to propose to use the pImpl idiom for the classes being included as a pointer instead of using pointers everywhere. In this way I thought we can have the best of both worlds:
Faster compile times: pimpl reduces compilation dependencies
To write your copy constructor and your copy assignment operator you just do this:
A::A(const A& rhs) : pImpl(std::make_unique<Impl>(*rhs.pImpl)) {}
A& A::operator=(const A& rhs) {
*pImpl = *rhs.pImpl;
return *this;
}
The constness is propagated to the member object.
At this point I had a discussion with my coworkers, they are arguing that pImpl is that it is not better than using pointers everywhere because of the following:
It reduces compilation dependencies less than using pointers, because if you are using pImpl you have to recompile the classes that includes your pImpl class when you change your public interface: if you were using just a pointer instead of the pImpl class you won't need to recompile even when changing the header file.
Now I am a little confused. I think that our actual convention is not really better than pImpl but I am not able to argue why.
So I have some questions:
Is the pImpl idiom a good alternative in this scenario?
Are there other downsides of the pattern we are using, except the ones that I mentioned?
Edit:
I am adding some examples to clarify the two approaces.
Approach with unique_ptr as member:
// B.h
#pragma once
class B {
int i = 42;
public:
void print();
};
// B.cpp
#include "B.h"
#include <iostream>
void B::print() { std::cout << i << '\n'; }
// A.h
#pragma once
#include <memory>
class B;
class A {
std::unique_ptr<B> b;
public:
A();
~A();
void printB();
};
// A.cpp
#include "A.h"
#include "B.h"
A::A() : b{ std::make_unique<B>() } {}
A::~A() = default;
void A::printB() { b->print(); }
Approach with pImpl:
// Bp.h
#pragma once
#include <memory>
class Bp {
struct Impl;
std::unique_ptr<Impl> m_pImpl;
public:
Bp();
~Bp();
void print();
};
// Bp.cpp
#include "Bp.h"
#include <iostream>
struct Bp::Impl {
int i = 42;
};
Bp::Bp() : m_pImpl{ std::make_unique<Impl>() } {}
Bp::~Bp() = default;
void Bp::print() { std::cout << m_pImpl->i << '\n'; }
// Ap.h
#pragma once
#include <memory>
#include "Bp.h"
class Ap {
Bp b;
public:
void printB();
};
// Ap.cpp
#include "Ap.h"
#include "Bp.h"
void Ap::printB() { b.print(); }
Main:
// main.cpp
#include "Ap.h"
#include "A.h"
int main(int argc, char** argv) {
A a{};
a.printB();
Ap aPimpl{};
aPimpl.printB();
}
Moreover I want to be more precise when I say that the first approach we don't need to recompile, this is inaccurate. It is true that we need to recompile less files:
If we change B.h we need to recompile only A.cpp, B.cpp.
If we change Bp.h we need to recompile Ap.cpp, Bp.cpp and main.cpp
After a while I have a broader understanding of the problem and finally I can answer to my own question.
It turned out that what I was saying was not completely correct.
In fact in the code below only Bp class is pImpl. If we change Ap to be pImpl aswell we obtain that, if we change Bp.h we need to recompile only Ap.cpp, Bp.cpp, which is the same of the corresponding solution with unique_ptrs.
Said that, I think I can say that the solution with pImpl seems in general better than the solution with unique_ptrs (we just have to pImpl the correct classes!).
For this reason we decided to switch to pImpl idiom as default for our classes.
I'm writing a C++ wrapper library around a number of different hardware libraries for embedded systems (firmware level), using various libraries from different vendors (C or C++). The API exposed by the header files should be vendor agnostic... all Vendor header libraries are not included in any of my header files.
A common pattern I have is making the vendor member data opaque, by only using a pointer to some "unknown" vendor struct/class/typedef/pod type.
// myclass.h
class MyClass
{
...
private:
VendorThing* vendorData;
};
and implementation (note: each implementation is vendor specific; all have the same *.h file)
// myclass_for_vendor_X.cpp
#include "vendor.h"
... {
vendorData->doSomething();
or
VendorAPICall(vendorData,...);
or whatever
The problem I have is that VendorThing can be lots of different things. It could be a class, struct, type or pod. I don't know, and I don't want to care in the header file. But if you pick the wrong one, then it doesn't compile if the vendor header file is included as well as my header file. For example, if this the actual declaration of VendorThing in "vendor.h":
typedef struct { int a; int b; } VendorThing;
Then you can't just forward-declare VendorThing as class VendorThing;. I don't care about what the type of VendorThing is at all, all I want is the public interface to think of it as void * (i.e allocate space for a pointer and that is it), and the implementation think of it using the correct pointer type.
Two solutions I have come across are the "d-pointer" method found in Qt, where you add a level of indirection by replacing VendorThing a new struct VendorThingWrapper
// myclass.h
struct VendorThingWrapper;
class MyClass
{
...
private:
VendorThingWrapper* vendorDataWrapper;
};
and in your cpp file
// myclass.cpp
#include "vendor.h"
struct VendorThingWrapper {
VendorThing* vendorData;
};
... {
vendorDataWrapper->vendorData->doSomething();
}
but this adds a second pointer dereference, which is not a huge deal, but as this is targeting embedded systems, I don't want to add that overhead just because the language can't do what I want.
The other thing is just declare it void
// myclass.h
class MyClass
{
...
private:
void* vendorDataUntyped;
};
and in the implememtation
//myclass.cpp
#include "vendor.h"
#define vendorData ((VendorThing*)vendorDataUntyped)
... {
vendorData->doSomething();
}
but #define's always leave a bad taste in my mouth. There must be something better.
You can avoid the additional pointer dereference by using:
#include "vendor.h"
struct VendorThingWrapper : public VendorThing {};
Of course, at that point, it makes more sense to use the name MyClassData instead of VendorThingWrapper.
MyClass.h:
struct MyClassData;
class MyClass
{
public:
MyClass();
~MyClass();
private:
MyClassData* myClassData;
};
MyClass.cpp:
struct MyClassData : public VendorThing {};
MyClass::MyClass() : myClassData(new MyClassData())
{
}
MyClass::~MyClass()
{
delete myClassData;
}
Update
I was able to compile and build the following program. The unnamed struct is not a problem.
struct MyClassData;
class MyClass
{
public:
MyClass();
~MyClass();
private:
MyClassData* myClassData;
};
typedef struct { int a; int b; } VendorThing;
struct MyClassData : public VendorThing
{
};
MyClass::MyClass() : myClassData(new MyClassData())
{
myClassData->a = 10;
myClassData->b = 20;
}
MyClass::~MyClass()
{
delete myClassData;
}
int main() {}
If you are willing to go the route of the VendorThingWrapper, then you simply allow the wrapper to contain the data itself, rather than a pointer to it. This gives you the abstraction layer and avoids the extra dereference.
// myclass.cpp
#include "vendor.h"
struct VendorThingWrapper {
VendorThing vendorData;
};
... {
vendorDataWrapper->vendorData.doSomething();
}
I've been playing with the Pimpl idiom and reaping all sorts of benefits from it. The only thing I haven't been too keen on is the feeling I get when I define the functions.
Once in the header (P def)
Once at the top of the .cpp (Impl def)
Once in the middle of the .cpp (Impl Impl)
Once at the lower end of the .cpp (P Impl)
I really enjoy cutting down code disparity and redundancy, and I feel like my code is less than well oiled when I have to add or change functions in even relatively complex Impls in my current project.
My question is, what effective ways are there to imply or template my classes in such a way that if I were to define a new function, I'd only have to write one explicit definition and implementation, and have the rest remain spatially close to the explicits in code; and if I were to change a function, the changes necessary would be as few as possible?
You might consider something along these lines:
An Interface class to minimize repeating declarations. The client will use the PublicImplementation class in their code.
Pimpl.h
#ifndef PIMPL_H_
#define PIMPL_H_
#include <memory> // std::unique_ptr
class Interface
{
public:
virtual ~Interface() {}
virtual void func_a() = 0;
virtual void func_b() = 0;
};
class PublicImplementation
{
// smart pointer provides exception safety
std::unique_ptr<Interface> impl;
public:
PublicImplementation();
// pass-through invoker
Interface* operator->() { return impl.get(); }
};
#endif // PIMPL_H_
Pimpl.cpp
#include "Pimpl.h"
#include <iostream>
class PrivateImplementation
: public Interface
{
public:
void func_a() override { std::cout << "a" << '\n'; }
void func_b() override { std::cout << "b" << '\n'; }
};
PublicImplementation::PublicImplementation()
: impl(new PrivateImplementation)
{
}
And finally this is what the client code does:
Main.cpp
#include "Pimpl.h"
int main()
{
PublicImplementation pi; // not a pointer
pi->func_a(); // pointer semantics
pi->func_b();
}
Let's postulate your header starts something like this:
class X
{
public:
...la de dah...
private:
struct Impl;
Impl* p_impl_;
};
Then when you add functions you have a choice to make:
do you have the X member function definition implement the logic, referring to p_impl_-> things all over the place, or
return p_impl->same_fn(all_the_args); and keep the logic inside the Impl class?
If you choose 1. then you end up with a function declaration in the header, and a (slightly messier than usual) definition in the matching implementation file.
If you choose 2. then you end up with a function declaration in the header file, a wrapping/forwarding definition in the matching implementation file, and at a minimum a definition in the Impl structure (I tend not to define the functions outside the Impl class definition - it's an implementation detail and the interface is not public anyway).
There is no generally desirable way to improve on this situation (i.e. macro hackery and extra code-generation scripts in your build process may occasionally be warranted, but very rarely).
It may not matter a whole heap, though it may be of interest that a variation on the second approach is to first implement a class that doesn't use the pimpl idiom (complete with proper header and optionally inline functions), you can then wrap it with a pimpl management object and forward functions to it, and in that way you keep the freedom to have some code somewhere some day decide it wants to use the functionality without using the pimpl wrapper, perhaps for improved performance / reduced memory usage at the cost of the recompilation dependency. You can also do this to make use of a specific instantiation of a template without exposing the template's code.
To illustrate this option (as requested in a comment), let's start with a silly non-pimpl class X in its own files, then create a Pimpl::X wrapper (the use of namespace and the same class name is entirely optional but facilitates flipping client code to use either, and a reminder - this isn't meant to be concise, the point here is to let a non-pImpl version be usable too):
// x.h
class X
{
public:
int get() const { return n_; } // inline
void operator=(int); // out-of-line definition
private:
int n_;
};
// x.c++
#include <x.h>
void X::operator=(int n) { n_ = n * 2; }
// x_pimpl.h
namespace Pimpl
{
class X
{
public:
X();
X(const X&);
~X();
X& operator=(const X&);
int get() const;
void operator=(int);
private:
struct Impl;
Impl* p_impl_;
};
}
x_pimpl.c++
#include <x.h>
namespace Pimpl
{
struct X::Impl
{
::X x_;
};
// the usual handling...
X() : p_impl_(new Impl) { }
X(const X& rhs) : p_impl(new Impl) { p_impl_->x_ = rhs.p_impl_->x_; }
~X() { delete p_impl_; }
X& operator=(const X& rhs) { p_impl_->x_ = rhs.p_impl_->x_; return *this; }
// the wrapping...
int X::get() const { return p_impl_->x_.get(); }
void X::operator=(int n) { p_impl_->x_ = n; }
}
If you opt for the above variation on 2, which makes the "implementation" a usable entity in it's own right, then yes - you may end up with 2 declarations and 2 definitions related to a single function, but then one of the definitions will be a simple wrapper/forwarding function which is only significantly repetitive and tedious if the functions are very short and numerous but have lots of parameters.
There's no requirement to treat the IMPL object to the same rules & standards as an object declaration in the .h file. By allowing member variables to be public (via a struct declaration), you don't need to implement an unnecessary wrapper layer. This is generally safe, since only the .cpp file has access to IMPL anyway.
Consider the following code that achieves the benefits of the PIMPL idiom without unnecessary code duplication:
// x.h
class X {
public:
X();
~X();
X(const X&) = delete;
X& operator =(const X&) = delete;
void set(int val);
int get() const;
private:
struct IMPL;
IMPL* impl;
};
// x.cpp
#include "x.h"
struct X::IMPL {
int val;
};
X::X() : impl(new IMPL) {}
X::~X() { delete impl; }
void X::set(int val)
{
impl->val = val;
}
int X::get() const
{
return impl->val;
}
// main.cpp
#include <iostream>
#include "x.h"
int main (int, char *[])
{
X x;
x.set(10);
std::cout << x.get() << std::endl;
return 0;
}
I'm just going to start by sumarizing to make sure I understand: You like the benefits of using pimpl, but dislike the amount of boilerplate code when adding or modifying functions?
In a nutshell, there is no template magic you can use to eliminate this boilerplate, but there are things to consider here as well:
You write code only once but read it many times, and you have at your disposal a variety of copy-paste capabilities. Initially creating the function isn't the majority of the time you will spend on this class. Compiling and maintaining is where your time will be spent.
Be sure to keep the public class API as simple as possible. The fewer functions you have in the public API the less boilerplate you have to write. You can make as many functions as you like in the impl and y ou only have to modify them there.
If you find yourself changing the public class API many many times, you might wish to slightly adjust your design process. Spend ten more minutes up front looking at/writing down use cases and you may reduce your API changes by 90%.
I have seen a few articles on generic programming and how you should never use virtual functions and templates together. I understand this idiom, as templates are decided at compilation, where virtual functions are not chosen until run-time (over simplification).
However, I have a bit of code that uses OO style and Generic style together and it seems to work the way I want.
My Question:
Is the following design bad practice. Mixing Polymorphism and Generic Code?
Is there any pit falls with my code below. (I know I should not inherit data members, but I have :-/).
#ifndef BaseTemplate_H
#define BaseTemplate_H
#include <vector>
template< class T >
class BaseTemplate {
public:
typedef std::vector<T*> pVT;
BaseTemplate(){}
virtual ~BaseTemplate(){};
virtual void Process()=0;
const pVT& getContainer(){ return m_pContainer; }
protected:
pVT m_pContainer;
private:
BaseTemplate( const BaseTemplate& cpy );
BaseTemplate& operator=( const BaseTemplate& rhs);
};
#endif
I inherit from the base class first by telling the base template what type I would like when inheriting.
This will allow me two inherit for multiple types, which I want to keep separate in my design.
#ifndef DerClassA_H
#define DerClassA_H
#include <iostream>
#include "BaseTemplate.h"
class DerClassA: public BaseTemplate<int> {
public:
DerClassA(){}
virtual ~DerClassA(){}
virtual void Process(){
std::cout << "HELLO I AM: DerClassA" << std::endl;
}//This will push_back objects to m_pContainer
private:
DerClassA( const DerClassA& cpy );
DerClassA& operator=( const DerClassA& rhs);
};
#endif
#ifndef DerClassB_H
#define DerClassB_H
#include <iostream>
#include "DerClassA.h"
class DerClassB: public DerClassA {
public:
DerClassB(){}
virtual ~DerClassB(){}
virtual void Process(){
std::cout << "HELLO I AM: DerClassB" << std::endl;
}//This will push_back objects to m_pContainer
private:
DerClassB( const DerClassB& cpy );
DerClassB& operator=( const DerClassB& rhs);
};
#endif
#include "DerClassA.h"
#include "DerClassB.h"
int main()
{
BaseTemplate<int> *pClassA = new DerClassA();
pClassA->Process();
DerClassA *pClassB = new DerClassB();
pClassB->Process();
delete pClassA;
delete pClassB;
return 0;
}
Is the following design bad practice. Mixing Polymorphism and Generic Code?
No, that's sometimes the right thing to do.
Is there any pit falls with my code below.
The container with raw pointers std::vector<T*> pVT; looks a bit fishy.
The base class destructor should probably be pure virtual.
I would use the C++11 syntax for making the class non-copyable.
You only need to make the base class non-copyable.
I don't see the need for dynamic allocation in your main function.
For the rest I don't see any immediate errors.
It's not possible to say whether or not your design is good without knowing what you are trying to do.
Consider the following:
PImpl.hpp
class Impl;
class PImpl
{
Impl* pimpl;
PImpl() : pimpl(new Impl) { }
~PImpl() { delete pimpl; }
void DoSomething();
};
PImpl.cpp
#include "PImpl.hpp"
#include "Impl.hpp"
void PImpl::DoSomething() { pimpl->DoSomething(); }
Impl.hpp
class Impl
{
int data;
public:
void DoSomething() {}
}
client.cpp
#include "Pimpl.hpp"
int main()
{
PImpl unitUnderTest;
unitUnderTest.DoSomething();
}
The idea behind this pattern is that Impl's interface can change, yet clients do not have to be recompiled. Yet, I fail to see how this can truly be the case. Let's say I wanted to add a method to this class -- clients would still have to recompile.
Basically, the only kinds of changes like this that I can see ever needing to change the header file for a class for are things for which the interface of the class changes. And when that happens, pimpl or no pimpl, clients have to recompile.
What kinds of editing here give us benefits in terms of not recompiling client code?
The main advantage is that the clients of the interface aren't forced to include the headers for all your class's internal dependencies. So any changes to those headers don't cascade into a recompile of most of your project. Plus general idealism about implementation-hiding.
Also, you wouldn't necessarily put your impl class in its own header. Just make it a struct inside the single cpp and make your outer class reference its data members directly.
Edit: Example
SomeClass.h
struct SomeClassImpl;
class SomeClass {
SomeClassImpl * pImpl;
public:
SomeClass();
~SomeClass();
int DoSomething();
};
SomeClass.cpp
#include "SomeClass.h"
#include "OtherClass.h"
#include <vector>
struct SomeClassImpl {
int foo;
std::vector<OtherClass> otherClassVec; //users of SomeClass don't need to know anything about OtherClass, or include its header.
};
SomeClass::SomeClass() { pImpl = new SomeClassImpl; }
SomeClass::~SomeClass() { delete pImpl; }
int SomeClass::DoSomething() {
pImpl->otherClassVec.push_back(0);
return pImpl->otherClassVec.size();
}
There has been a number of answers... but no correct implementation so far. I am somewhat saddened that examples are incorrect since people are likely to use them...
The "Pimpl" idiom is short for "Pointer to Implementation" and is also referred to as "Compilation Firewall". And now, let's dive in.
1. When is an include necessary ?
When you use a class, you need its full definition only if:
you need its size (attribute of your class)
you need to access one of its method
If you only reference it or have a pointer to it, then since the size of a reference or pointer does not depend on the type referenced / pointed to you need only declare the identifier (forward declaration).
Example:
#include "a.h"
#include "b.h"
#include "c.h"
#include "d.h"
#include "e.h"
#include "f.h"
struct Foo
{
Foo();
A a;
B* b;
C& c;
static D d;
friend class E;
void bar(F f);
};
In the above example, which includes are "convenience" includes and could be removed without affecting the correctness ? Most surprisingly: all but "a.h".
2. Implementing Pimpl
Therefore, the idea of Pimpl is to use a pointer to the implementation class, so as not to need to include any header:
thus isolating the client from the dependencies
thus preventing compilation ripple effect
An additional benefit: the ABI of the library is preserved.
For ease of use, the Pimpl idiom can be used with a "smart pointer" management style:
// From Ben Voigt's remark
// information at:
// http://en.wikibooks.org/wiki/More_C%2B%2B_Idioms/Checked_delete
template<class T>
inline void checked_delete(T * x)
{
typedef char type_must_be_complete[ sizeof(T)? 1: -1 ];
(void) sizeof(type_must_be_complete);
delete x;
}
template <typename T>
class pimpl
{
public:
pimpl(): m(new T()) {}
pimpl(T* t): m(t) { assert(t && "Null Pointer Unauthorized"); }
pimpl(pimpl const& rhs): m(new T(*rhs.m)) {}
pimpl& operator=(pimpl const& rhs)
{
std::auto_ptr<T> tmp(new T(*rhs.m)); // copy may throw: Strong Guarantee
checked_delete(m);
m = tmp.release();
return *this;
}
~pimpl() { checked_delete(m); }
void swap(pimpl& rhs) { std::swap(m, rhs.m); }
T* operator->() { return m; }
T const* operator->() const { return m; }
T& operator*() { return *m; }
T const& operator*() const { return *m; }
T* get() { return m; }
T const* get() const { return m; }
private:
T* m;
};
template <typename T> class pimpl<T*> {};
template <typename T> class pimpl<T&> {};
template <typename T>
void swap(pimpl<T>& lhs, pimpl<T>& rhs) { lhs.swap(rhs); }
What does it have that the others didn't ?
It simply obeys the Rule of Three: defining the Copy Constructor, Copy Assignment Operator and Destructor.
It does so implementing the Strong Guarantee: if the copy throws during an assignment, then the object is left unchanged. Note that the destructor of T should not throw... but then, that is a very common requirement ;)
Building on this, we can now define Pimpl'ed classes somewhat easily:
class Foo
{
public:
private:
struct Impl;
pimpl<Impl> mImpl;
}; // class Foo
Note: the compiler cannot generate a correct constructor, copy assignment operator or destructor here, because doing so would require access to Impl definition. Therefore, despite the pimpl helper, you will need to define manually those 4. However, thanks to the pimpl helper the compilation will fail, instead of dragging you into the land of undefined behavior.
3. Going Further
It should be noted that the presence of virtual functions is often seen as an implementation detail, one of the advantages of Pimpl is that we have the correct framework in place to leverage the power of the Strategy Pattern.
Doing so requires that the "copy" of pimpl be changed:
// pimpl.h
template <typename T>
pimpl<T>::pimpl(pimpl<T> const& rhs): m(rhs.m->clone()) {}
template <typename T>
pimpl<T>& pimpl<T>::operator=(pimpl<T> const& rhs)
{
std::auto_ptr<T> tmp(rhs.m->clone()); // copy may throw: Strong Guarantee
checked_delete(m);
m = tmp.release();
return *this;
}
And then we can define our Foo like so
// foo.h
#include "pimpl.h"
namespace detail { class FooBase; }
class Foo
{
public:
enum Mode {
Easy,
Normal,
Hard,
God
};
Foo(Mode mode);
// Others
private:
pimpl<detail::FooBase> mImpl;
};
// Foo.cpp
#include "foo.h"
#include "detail/fooEasy.h"
#include "detail/fooNormal.h"
#include "detail/fooHard.h"
#include "detail/fooGod.h"
Foo::Foo(Mode m): mImpl(FooFactory::Get(m)) {}
Note that the ABI of Foo is completely unconcerned by the various changes that may occur:
there is no virtual method in Foo
the size of mImpl is that of a simple pointer, whatever what it points to
Therefore your client need not worry about a particular patch that would add either a method or an attribute and you need not worry about the memory layout etc... it just naturally works.
With the PIMPL idiom, if the internal implementation details of the IMPL class changes, the clients do not have to be rebuilt. Any change in the interface of the IMPL (and hence header file) class obviously would require the PIMPL class to change.
BTW,
In the code shown, there is a strong coupling between IMPL and PIMPL. So any change in class implementation of IMPL also would cause a need to rebuild.
Consider something more realistic and the benefits become more notable. Most of the time that I have used this for compiler firewalling and implementation hiding, I define the implementation class within the same compilation unit that visible class is in. In your example, I wouldn't have Impl.h or Impl.cpp and Pimpl.cpp would look something like:
#include <iostream>
#include <boost/thread.hpp>
class Impl {
public:
Impl(): data(0) {}
void setData(int d) {
boost::lock_guard l(lock);
data = d;
}
int getData() {
boost::lock_guard l(lock);
return data;
}
void doSomething() {
int d = getData();
std::cout << getData() << std::endl;
}
private:
int data;
boost::mutex lock;
};
Pimpl::Pimpl(): pimpl(new Impl) {
}
void Pimpl::doSomething() {
pimpl->doSomething();
}
Now no one needs to know about our dependency on boost. This gets more powerful when mixed together with policies. Details like threading policies (e.g., single vs multi) can be hidden by using variant implementations of Impl behind the scenes. Also notice that there are a number of additional methods available in Impl that aren't exposed. This also makes this technique good for layering your implementation.
In your example, you can change the implementation of data without having to recompile the clients. This would not be the case without the PImpl intermediary. Likewise, you could change the signature or name of Imlp::DoSomething (to a point), and the clients wouldn't have to know.
In general, anything that can be declared private (the default) or protected in Impl can be changed without recompiling the clients.
In non-Pimpl class headers the .hpp file defines the public and private components of your class all in one big bucket.
Privates are closely coupled to your implementation, so this means your .hpp file really can give away a lot about your internal implementation.
Consider something like the threading library you choose to use privately inside the class. Without using Pimpl, the threading classes and types might be encountered as private members or parameters on private methods. Ok, a thread library might be a bad example but you get the idea: The private parts of your class definition should be hidden away from those who include your header.
That's where Pimpl comes in. Since the public class header no longer defines the "private parts" but instead has a Pointer to Implementation, your private world remains hidden from logic which "#include"s your public class header.
When you change your private methods (the implementation), you are changing the stuff hidden beneath the Pimpl and therefore clients of your class don't need to recompile because from their perspective nothing has changed: They no longer see the private implementation members.
http://www.gotw.ca/gotw/028.htm
Not all classes benefit from p-impl. Your example has only primitive types in its internal state which explains why there's no obvious benefit.
If any of the members had complex types declared in another header, you can see that p-impl moves the inclusion of that header from your class's public header to the implementation file, since you form a raw pointer to an incomplete type (but not an embedded field nor a smart pointer). You could just use raw pointers to all your member variables individually, but using a single pointer to all the state makes memory management easier and improves data locality (well, there's not much locality if all those types use p-impl in turn).