Two ways for separating interface from implementation

Usually, the providers of a program want to hide the module’s concrete technique implementation. In this post, two ways for this goal will be introduced. One is called pImpl, another is pure abstract class.

pImpl

pImpl means “pointer to Implementation” which is a C++ programming technique. It can remove the implementation details of a class from its object representation by placing them in a separate class. pImpl can break the compilation dependency, changes to the implementation will not cause recompilation. So if a library uses pImpl as its interface, new version of the library may change implementation while remaining the interface with older versions.

As the object of the interface type controls the lifetime of object of the implementation type, the pointer to the implementation type is usually std::unique_ptr.

widget.h
1
2
3
4
5
6
7
8
9
10
11
12
#include <memory>
using namespace std;
class widget {
public:
widget();
void Dosomething();
private:
class impl; // forward declaration of the implementation class
std::unique_ptr<impl> pImpl; // to the forward-declared implementation class
};
widget.cpp
1
2
3
4
5
6
7
8
9
10
#include "widget.h"
#include "Impl.h"
widget::widget() {
pImpl.reset(new Impl());
}
widget::Dosomething() {
pImpl -> Dosomething();
}
Impl.h
1
2
3
4
5
6
7
8
9
10
11
#include "widget.h"
using namespace std;
class widget::Impl {
public:
void Dosomething();
private:
// some private members,
// that will be hiden in class widget.
};
Impl.cpp
1
2
3
4
5
#include "widget.h"
void widget::Impl::Dosomething() {
// do something.
}

Pure abstract class

Pure abstract class is the class which includes pure virtual functions as its member functions. This type of class should not be instantiated but used as a base class. Usually, it plays a role as an interface class in programming.

ITest.h
1
2
3
4
5
6
7
8
9
10
11
12
#include <memory>
using namespace std;
class ITest {
public:
virtual void Dosomething() = 0;
};
// define a factory.
shared_ptr<ITest> Test_factory();
Test.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include "ITest.h"
using namespace std;
class Test : public ITest {
public:
virtaul void Dosomething();
private:
Test();
Test(const Test&);
Test& operator=(const Test&);
protected:
shared_ptr<ITest> Test_factory();
};
Test.cpp
1
2
3
4
5
6
7
8
9
#include "Test.h"
void Test::Dosomething() {
// do something.
}
shared_ptr<ITest> Test_factory() {
return shared_ptr<ITest>(new Test);
}

To set constructor, copy constructor and assignment operator as private member, the object of implementation class can only be instantiated by factory function. Meanwhile, the factory function should be included as a protect member of implementation class for accessing its private constructor.