HiveBrain v1.2.0
Get Started
← Back to all entries
patterncppMinor

C++: Hiding class implementation detail generic

Submitted by: @import:stackexchange-codereview··
0
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:

#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 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.