Differentiating pimpl idiom classes in c++

G

Graham Reitz

What are good strategies for selecting, either at run-time or compile
time, various pimpl'ed implementations? While retaining the ability
to switch implementations without recompiling.

Boost has an example but with only one implementation class: (what
would an example with 2 implementation classes look like?)

http://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/sp_techniques.html#pimpl

The pimpl'ed class cpp file has to include at least one implementation
header file. Is there a method to avoid changing that included header
when switching implementations?

Or, are we using the pimpl idiom incorrectly?

thanks,
graham
 
N

Noah Roberts

Graham said:
What are good strategies for selecting, either at run-time or compile
time, various pimpl'ed implementations? While retaining the ability
to switch implementations without recompiling.

Boost has an example but with only one implementation class: (what
would an example with 2 implementation classes look like?)

http://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/sp_techniques.html#pimpl

The pimpl'ed class cpp file has to include at least one implementation
header file. Is there a method to avoid changing that included header
when switching implementations?

Or, are we using the pimpl idiom incorrectly?

You need to abstract your pimpl and make a factory. You'll always need
to recompile if you add a new pimpl type, but you can switch between
them. It will no longer be a pimpl at this point.

It sounds like what you really want is a State. Look up that pattern.
 
B

Brian Szmyd

What are good strategies for selecting, either at run-time or compile
time, various pimpl'ed implementations? While retaining the ability
to switch implementations without recompiling.

Boost has an example but with only one implementation class: (what
would an example with 2 implementation classes look like?)

http://www.boost.org/doc/libs/1_35_0/libs/smart_ptr/sp_techniques.html#pimpl

The pimpl'ed class cpp file has to include at least one implementation
header file. Is there a method to avoid changing that included header
when switching implementations?

Or, are we using the pimpl idiom incorrectly?

thanks,
graham

Funny you asked, as I just finished doing exactly this for a project I'm
working on. Here's what I did:

// Factory.h
#include <map>
#include <string>
template <typename T>
class Factory
{
public:
typedef std::map<std::string, typename T::constructor_type> Map;

static Factory<T>* getFactory()
{
if ( ! m_instance )
m_instance = new Factory<T>;
return m_instance;
}

typename T::constructor_type createKind( std::string output_kind )
{
typename Map::iterator it;
if if ( ( it = constructorMap.find( output_kind ) ) != constructorMap.end() )
return (*it).second;
// Throw something here
}

void void registerKind( std::string kind, typename T::constructor_type
constructor) {
constructorMap[kind] = constructor;
}

private:
Map constructorMap;
static Factory<T>* m_instance;
};

// FooImpl.h
#include <boost/function.hpp>
#include <boost/shared_ptr.hpp>
#include "Factory.h"
FooImpl
{
public:
typedef typedef boost::function<boost::shared_ptr<FooImpl>()>
constructor_type; static Factory<FooImpl> factory;
};

// FooImpl.cpp
Factory<FooImpl> FooImpl::factory;

// FooFake.cpp
#include "FooImpl.h"
class FooFake :
public FooImpl
{
private:
struct FooFakeCreator
{
FooFakeCreator oFakeCreator () {
FooImpl::factory.getFactory()->registerKind("Fake", FooFakeCreator::create );
static static boost::shared_ptr<FooImpl> create () { return
boost::shared_ptr<FooImpl>( new FooFake() ); } }
static FooFakeCreator m_creator;
};

FooFake::FooFakeCreator FooFake::m_creator;


You could probably clean this up, but it allows your users to be agnostic to
the different implementations. I didn't include the actual Foo object, that
in my case contains a weak pointer to a FooImpl. My implementation also
requires the caller to FooImpl::factory->createKind(string) to provide the
type, but this could be read in from a config file and you could remove this
requirement. Have some sort of factory registry that createKind would look
into.

This may or may not have a "pattern name", let me know someone if it does.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,955
Messages
2,570,117
Members
46,705
Latest member
v_darius

Latest Threads

Top