We have central classes and functions in our big project to abstract from the actual platform types, e.g. mutex, file, thread etc. instead of having "fopen" everywhere in the code. While this is good, I would like to go even further and don't have any system includes in the header files (like #include <windows.h>
), which would be true platform abstraction and faster compilation. On the downside you cannot just typedef to a system type (e.g. Windows HANDLE).
class RwMutex
{
// .....
private:
struct Impl;
Impl* m_Impl;
}
class RwMutex {
public:
bool LockRead() {return RwMutexLockRead( this );}
private:
char m_AnonymousMember[ 16 ];
}
bool RwMutexLockRead( RwMutex* p );
Maybe I'm to eager on it, but it would be cool if the huge amount of project code would be clean of any platform-dependent includes, maybe enforced by the -nostdinc
option.
The Platform Abstraction Layer (PAL) addresses this heterogeneity and provides the container with a uniform interface for accessing the relevant hardware and operating system information, thus allowing the rest of the container to run unmodified on any supported platform.
There are three different layers of abstraction in computer system such as the concrete architecture at the system level, the abstract and concrete architecture at the processor level, and the abstract and concrete architecture at the micro-machine level.
Examples of software models that use layers of abstraction include the OSI model for network protocols, OpenGL, and other graphics libraries, which allow the separation of concerns to facilitate interoperability and platform independence.
Option 1 using pointers is a bad idea. Use either boost::scoped_ptr
or, if you can, std::unique_ptr
.
Option 2, as you implement it, should not be used. See GotW #28: The Fast Pimpl Idiom. In C++11 however, this can be done correctly using std::aligned_storage<>
. I once wrote a pimpl_ptr<T, Size, Align=default>
that does the casting, copying, destructor call for you and checks that you have chosen the right Size
.
In general, use pimpl unless you have profiled and shown that this is the bottleneck.
But as always, don't reinvent the wheel. Mutex and Threads are part of the new C++11 standard, so either upgrade the compiler or use Boost instead. For files use Boost. The reasoning is, that many parts of the new C++11 library are taken from Boost.
Why even have an Implementation object? Your code will not just change on the same platform, you'll be using the same implementation on the platform that your currently using at the time. Define the interface in the header, and provide various *.cpp files for the implementation for each platform you are targeting for. Using #ifndef, #else, etc.
e.g. Your file system may look like this:
include/
RwMutex.hpp
// etc...
src/
RwMutex/
RwMutexWin32.cpp
RwMutexUnix.cpp
// etc...
Here's what RwMutexWin32.cpp may look like:
#ifdef MYLIBPREFIX_PLATFORM_WIN32
#include "RwMutex.hpp"
#include <Windows.h>
// implement the Windows version of the RwMutex class
Another example may be to look at SDL, or some other cross-platform library written in C or C++. They mainly use the preprocessor system. It's not likely you'd want to change what the Impl object points to (i.e. a Unix implementation on a Windows machine wouldn't make sense, nor would it compile).
And of course, if you really want to do this, I'd recommend using CMake. But as other people have suggested, you should try to use other libraries, such as boost or the standard library, it's already written for you.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With