views:

407

answers:

6

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: http://stackoverflow.com/questions/976208/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.

+1  A: 

If you're on Windows, and using C++/CLI, this becomes fairly easy. The .NET framework provides this capability via reflection, and it works very cleanly in managed code.

In native C++, this gets a little bit trickier, as there's no simple way to query the library or application for runtime information. There are many frameworks that provide this (just look for IoC, DI, or plugin frameworks), but the simplest means of doing it yourself is to have some form of configuration which a factory method can use to register themselves, and return an implementation of your specific base class. You'd just need to implement loading a DLL, and registering the factory method - once you have that, it's fairly easy.

Reed Copsey
I am on windows, but, alas, the program needs to run on linux as well (so I'm using GNU compiler). I don't need to go so far as querying the runtime. I would, in fact, prefer a compile-time (or rather, a link-time) solution.
cheshirekow
A: 

There is no way to query the subclasses of a class in (native) C++. How do you create the instances? Consider using a Factory Method allowing you to iterate over all subclasses you are working with. When you create an instance like this, it won't be possible to forget adding a new subclass later.

h0b0
That's exactly what I want to do, but I want a clean way to do the book keeping so I dont have to update the code for that factory method every time I write a new subclass.
cheshirekow
+3  A: 

I vaguely remember doing something similar to this many years ago. Your option (2) is pretty much what I did. In that case it was a std::map of std::string to std::typeinfo. In each, .cpp file I registered the class like this:

static dummy = registerClass (typeid (MyNewClass));

registerClass takes a type_info object and simply returns true. You have to initialize a variable to ensure that registerClass is called during startup time. Simply calling registerClass in the global namespace is an error. And making dummy static allow you to reuse the name across compilation units without a name collision.

eduffy
Ok, sounds good. I'm not 100% confident with my knowledge on static initialization, but if this is a feasible plan I'll start trying it out. The typeid operator will be helpful. I'll come back and make this the answer if I get it to work.
cheshirekow
Rereading answers I think this solution is the best one (for now ?). No need to clutter the code with factory methods, it works with existing code, and it is more direct that what I have proposed. As C++ have not many RTTI mechanisms I don't think you can do better ... +1 man.
neuro
And how do you create a registered class?
TimW
+5  A: 

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()
{
    //....
}
TimW
And you can wrap the registration in a macro to make it easier to use: REGISTER_CLASS(ClassY)
Bojan Resnik
Thank you, that code snippet is very helpful. Is there any particular reason to use this extra class rather than storing the map as a static member of the interface. As far as I can tell, it provides a sensible "create()" method, but any other reason. This may be especially useful as a generic singleton, then I can instantiate one for each of the interfaces that I know I will be extending in the future.
cheshirekow
+1 for the coding effort :)
neuro
@cheshirekow single responsibility principle
TimW
@TimW, thanks a ton. I think this is a very good solution. I've implemented it and it works quite well. I posted my code to share: http://cheshirekow.com/blog/?p=40
cheshirekow
+1  A: 

Something you can consider is an object counter. This way you don't need to change every place you allocate but just implementation definition. It's an alternative to the factory solution. Consider pros/cons.

An elegant way to do that is to use the CRTP : Curiously recurring template pattern. The main example is such a counter :)

This way you just have to add in your concrete class implementation :

class X; // your interface

class MyConcreteX : public counter<X>
{
    // whatever
};

Of course, it is not applicable if you use external implementations you do not master.

EDIT:

To handle the exact problem you need to have a counter that count only the first instance.

my 2 cents

neuro
That is a very clever way to approach the problem. I assume that counter<X> extends X and contains a static object count, incremented on construction and decremented on destruction. I think this is a little indirect though and what I need isn't actually an object count, but a way to enumerate available subclasses.
cheshirekow
Not exactly, that use the CRTP pattern which is worth a look. See the link in my answer as the code for such a counter is given. The idea in my answer was to use an object counter, that counts only the first instanciation. I know that there cons like the need to instantiate at least one object (can be a static dummy one though), but seems to be better than the factory method solution.
neuro
+2  A: 

I referred to this article to implement a self-registering class factory similar to the one described in TimW's answer, but it has the nice trick of using a templated factory proxy class to handle the object registration. Well worth a look :)

Self-Registering Objects in C++ -> http://www.ddj.com/184410633

Edit

Here's the test app I did (tidied up a little ;):

object_factory.h

#include <string>
#include <vector>
// Forward declare the base object class
class Object;
// Interface that the factory uses to communicate with the object proxies
class IObjectProxy {
public:
    virtual Object* CreateObject() = 0;
    virtual std::string GetObjectInfo() = 0;
};
// Object factory, retrieves object info from the global proxy objects
class ObjectFactory {
public:
    static ObjectFactory& Instance() {
        static ObjectFactory instance;
        return instance;
    }
    // proxies add themselves to the factory here 
    void AddObject(IObjectProxy* object) {
        objects_.push_back(object);
    }
    size_t NumberOfObjects() {
        return objects_.size();
    }
    Object* CreateObject(size_t index) {
        return objects_[index]->CreateObject();
    }
    std::string GetObjectInfo(size_t index) {
        return objects_[index]->GetObjectInfo();
    }

private:
    std::vector<IObjectProxy*> objects_;
};

// This is the factory proxy template class
template<typename T>
class ObjectProxy : public IObjectProxy {
public:
    ObjectProxy() {
        ObjectFactory::Instance().AddObject(this);
    }        
    Object* CreateObject() {
        return new T;
    }
    virtual std::string GetObjectInfo() {
        return T::TalkToMe();
    };    
};

objects.h

#include <iostream>
#include "object_factory.h"
// Base object class
class Object {
public:
    virtual ~Object() {}
};
class ClassA : public Object {
public:
    ClassA() { std::cout << "ClassA Constructor" << std::endl; }
    ~ClassA() { std::cout << "ClassA Destructor" << std::endl; }
    static std::string TalkToMe() { return "This is ClassA"; }
};
class ClassB : public Object {
public:
    ClassB() { std::cout << "ClassB Constructor" << std::endl; }
    ~ClassB() { std::cout << "ClassB Destructor" << std::endl; }
    static std::string TalkToMe() { return "This is ClassB"; }
};

objects.cpp

#include "objects.h"
// Objects get registered here
ObjectProxy<ClassA> gClassAProxy;
ObjectProxy<ClassB> gClassBProxy;

main.cpp

#include "objects.h"
int main (int argc, char * const argv[]) {
    ObjectFactory& factory = ObjectFactory::Instance();
    for (int i = 0; i < factory.NumberOfObjects(); ++i) {
        std::cout << factory.GetObjectInfo(i) << std::endl;
        Object* object = factory.CreateObject(i);
        delete object;
    }
    return 0;
}

output:

This is ClassA
ClassA Constructor
ClassA Destructor
This is ClassB
ClassB Constructor
ClassB Destructor
mash
But then the registration is implicit and you need to create an instance of every concrete class. I prefer the explicit registration without object creation.
TimW
You create a factory proxy for each concrete class, but the classes themselves are only created when required, via the factory. I'll edit the answer with some code when I get home this evening :)
mash
thanks for the clarification
TimW