There are several techniques to hide the implementation details of a class, one of which are the idioms pimpl
and fast pimpl
.
Their essence is to create some opaque (hidden) class where the implementation details will be located,
and put a pointer to the hidden class in the public class.
The difference between pimpl
and fast pimpl
is that in the first case you put a pointer to the hidden class in the
public class, and in the constructor you allocate and initialize the hidden class. The disadvantage of this approach is
that the public class and the hidden class are in different places in the heap, which is not very cache friendly.
In fast pimpl
you create a public class and allocate additional space for the hidden class, and in the constructor you
initialize the additional space with your hidden class, thus all your data in the heap will lie next to each other -
this will give a performance boost. Among the disadvantages of fast pimpl
it should be noted that you will need to
know the size and aligment of the hidden class at the compilation stage.
Use CPM.cmake (more info)
CPMAddPackage("gh:alexv-ds/cpp-fast-pimpl@2.0.1")
target_link_libraries(example PRIVATE fpimpl::fpimpl)
Add this repository as a submodule of your project and add the dirrectory in your CMakeListst.txt
add_subdirectory("path/to/fpimpl/subproject")
target_link_libraries(example PRIVATE fpimpl::fpimpl)
Due to the fact that this library is just a single header file. Simply copy the header file to the location you want. And use it.
MyClass.hpp
class MyClass {
public:
//ctor, dtor - required
MyClass();
~MyClass();
//copy semantics - optional
MyClass(const MyClass&);
MyClass& operator=(const MyClass&);
//move semantics - optional
MyClass(MyClass&&);
MyClass& operator=(MyClass&&);
private:
struct Impl;
fpimpl<Impl, 16, 8> impl; //16 - Impl struct size, 8 - Impl struct aligment
};
MyClass.cpp
struct MyClass::Impl {
//some impl
};
//ctor, dtor - required
MyClass::MyClass() = default;
MyClass::~MyClass() = default;
//copy semantics - optional
MyClass::MyClass(const MyClass&) = default;
MyClass::MyClass& operator=(const MyClass&) = default;
//move semantics - optional
MyClass(MyClass&&) = default;
MyClass& operator=(MyClass&&) = default;