C++ – How to keep track of (enumerate) all classes that implement an interface

cclassenumerate

I have a situation where I have an interface that defines how a certain class behaves in order to fill a certain role in my program, but at this point in time I'm not 100% sure how many classes I will write to fill that role. However, at the same time, I know that I want the user to be able to select, from a GUI combo/list box, which concrete class implementing the interface that they want to use to fill a certain role. I want the GUI to be able to enumerate all available classes, but I would prefer not to have to go back and change old code whenever I decide to implement a new class to fill that role (which may be months from now)

Some things I've considered:

  1. using an enumeration
    • Pros:
      1. I know how to do it
    • Cons
      1. I will have to update update the enumeration when I add a new class
      2. ugly to iterate through
  2. using some kind of static list object in the interface, and adding a new element from within the definition file of the implementing class
    • Pros:
      1. Wont have to change old code
    • Cons:
      1. Not even sure if this is possible
      2. Not sure what kind of information to store so that a factory method can choose the proper constructor ( maybe a map between a string and a function pointer that returns a pointer to an object of the interface )

I'm guessing this is a problem (or similar to a problem) that more experienced programmers have probably come across before (and often), and there is probably a common solution to this kind of problem, which is almost certainly better than anything I'm capable of coming up with. So, how do I do it?

(P.S. I searched, but all I found was this, and it's not the same: How do I enumerate all items that implement a generic interface?. It appears he already knows how to solve the problem I'm trying to figure out.)

Edit: I renamed the title to "How can I keep track of… " rather than just "How can I enumerate…" because the original question sounded like I was more interested in examining the runtime environment, where as what I'm really interested in is compile-time book-keeping.

Best Answer

Create a singleton where you can register your classes with a pointer to a creator function. In the cpp files of the concrete classes you register each class.
Something like this:

class Interface;
typedef boost::function<Interface* ()> Creator;

class InterfaceRegistration
{
    typedef map<string, Creator> CreatorMap;
public:
    InterfaceRegistration& instance() {  
        static InterfaceRegistration interfaceRegistration;
        return interfaceRegistration;
    }

    bool registerInterface( const string& name, Creator creator )
    {
        return (m_interfaces[name] = creator);
    }

    list<string> names() const
    {
        list<string> nameList;  
        transform(
            m_interfaces.begin(), m_interfaces.end(), 
            back_inserter(nameList) 
            select1st<CreatorMap>::value_type>() );
    }

    Interface* create(cosnt string& name ) const 
    { 
        const CreatorMap::const_iterator it 
            = m_interfaces.find(name);  
        if( it!=m_interfaces.end() && (*it) )
        {
            return (*it)();
        }
        // throw exception ...
        return 0;
    }

private:
    CreatorMap m_interfaces;
};


// in your concrete classes cpp files
namespace {
bool registerClassX = InterfaceRegistration::instance("ClassX", boost::lambda::new_ptr<ClassX>() );
}

ClassX::ClassX() : Interface()
{
    //....
}

// in your concrete class Y cpp files
namespace {
bool registerClassY = InterfaceRegistration::instance("ClassY", boost::lambda::new_ptr<ClassY>() );
}

ClassY::ClassY() : Interface()
{
    //....
}