patterncppMinor
C++: Hiding class implementation detail generic
Viewed 0 times
genericdetailhidingimplementationclass
Problem
It always bugged me that you would have to write your private class members inside the header files in C++. This means that everytime you change you implementation, client code has to be rebuild.
I found thise site which describes how to hide implementation detail in C++: http://www.octopull.demon.co.uk/c++/implementation_hiding.html
However I also wanted the code to be generic, so that I didn't have to rewrite the same code for each and every class I create. Here is what I got:
Example usage:
I always hear that preprocessor macros are dirty and should not be used in C++, and I agree to some degree. However I could not realize what I wanted using templates.
So what do you think?
I found thise site which describes how to hide implementation detail in C++: http://www.octopull.demon.co.uk/c++/implementation_hiding.html
However I also wanted the code to be generic, so that I didn't have to rewrite the same code for each and every class I create. Here is what I got:
#define TL_UTILS_IMPL_DECL(member) \
private: \
class impl; \
impl* member;
#define TL_UTILS_IMPL_START(t_class, parent) \
class t_class::impl \
{ \
public: \
t_class* parent; \
impl(t_class* self) \
: parent(self) \
{}
#define TL_UTILS_IMPL_END() \
};
#define TL_UTILS_IMPL_INIT(member) \
member = new impl(this);
#define TL_UTILS_IMPL_TERM(member) \
delete member;
#define TL_UTILS_IMPL_PREFIX(t_class) \
t_class::impl::Example usage:
// Header file:
class foo
{
TL_UTILS_IMPL_DECL(m)
public:
foo();
~foo();
};
// Source file:
TL_UTILS_IMPL_START(foo, p)
void bar();
TL_UTILS_IMPL_END()
foo::foo()
{
TL_UTILS_IMPL_INIT(m)
// from here on we can use the private
// data and methods stored in m
m->bar();
}
foo::~for()
{
TL_UTILS_IMPL_TERM(m)
}
void TL_UTILS_IMPL_PREFIX(foo) bar()
{
// do something useful
// use p as a pointer to the parent class instance
}I always hear that preprocessor macros are dirty and should not be used in C++, and I agree to some degree. However I could not realize what I wanted using templates.
So what do you think?
- Is the use of preprocessor macros justified here?
- Is the code safe?
- Any improvements you can think of?
Solution
Is the use of preprocessor macros justified here?
To me it seems like overkill. The only non-trivial macro is
Is the code safe?
You need to apply the "Rule of Three" - either implement, or remove, the copy constructor and copy assignment operator. I generally use
To me it seems like overkill. The only non-trivial macro is
TL_UTILS_IMPL_START, and that will almost certainly never be useful - usually, the impl class won't need a back-pointer to its wrapper class, but will need other constructor arguments, so you'll usually have to write your own class-specific constructor and initialiser anyway. The other macros are just as verbose as, and much less self-explanatory than, the code they replace.Is the code safe?
You need to apply the "Rule of Three" - either implement, or remove, the copy constructor and copy assignment operator. I generally use
boost::scoped_ptr for the implementation pointer, which sorts this out for me (as well as removing the need for a destructor body).Context
StackExchange Code Review Q#5160, answer score: 3
Revisions (0)
No revisions yet.