Archive for August, 2009
Instanciate Objects of Unknown Type from Their Parent Interface
Posted by cheshirekow in C++ Discoveries and Notes, Programming on August 14, 2009
This is based on my previous two posts on Static Interfaces in C++ and Keep Track of and Enumerate All Sub-classes of a Particular Interface. The idea is that I want my code to be extensible in the feature without requiring any re-writing of the current code base. The code base operates on generic objects via their interfaces, so as long as newly-coded classes properly extend those interfaces, the program should know how to handle them. The problem is, how can we write the program in such a manner that a user interface can enumerate available options for implementations of a particular interface, and how can we instantiate those objects?
In Keep Track of and Enumerate All Sub-classes of a Particular Interface I showed how to maintain a registry of classes deriving from a given interface, which handles the first problem, but there is a limitation in that all of these classes must provide a factory method that takes no parameters (void input). I decided that, for my project, this was not acceptable and I needed a way to define the creation parameters as part of the factory methods, whereas the creation parameters may be different for particular interfaces.
In Keep Track of and Enumerate All Sub-classes of a Particular Interface I showed how we can enforce the requirement of a static method in derived classes with a particular signature using a template interface.
In this post I will combine the two so that we can create a registry of classes that inherit from a particular interface, and provide a static factory method for creating objects of that interface, using a particular creation method signature unique to that interface. The registry will pair class names with function pointers that match the specific signature of the interface the class is being registered for.
Disclaimer: I do not claim this is the “best” way to handle this issue. This is just what I came up with. It happens to be pretty involved and overly indirect, which means it’s probably bad design. It is, however, an extremely interesting exercise in generic programming.
Prequil: the code will require these later so there they are:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | /** * file RegistryTest.cpp * date: Aug 14, 2009 * brief: * * detail: */ #include <set> #include <map> #include <string> #include <iostream> using namespace std; |
Ok, so lets begin. First let’s define a couple of interfaces that we’re interested in.
16 17 18 | class InterfaceA{}; class InterfaceB{}; class InterfaceC{}; |
Now we create a template class whose sole purpose is to create a per-interface typedef
of the function signature that is necessary for instantiating and object of that class. Is it really possible that all sub-objects can be instantiated with the same parameters? If that’s the case, shouldn’t they all be combined into a single class that just contains that information as private members? Probably, but in my case these parameters are more like a “bare minimum” for instantiation, and then many more parameters are set by the user. It makes sense to me, I promise. If it doesn’t to you, you don’t have to use this.
19 20 21 22 23 24 | template< typename InterfaceType > class Factory { public: typedef InterfaceType*(*Creator)(void); }; |
Creator
is now a typedef
that aliases a function pointer that takes no parameters. Wait, isn’t that what we had before? Yes, but now we make a couple of template specializations to define the different signatures for our specific interfaces. These specializations would normally be in the file that contained the interface declaration.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /// specializations can define other creators, this one requires an int template<> class Factory<InterfaceB> { public: typedef InterfaceB*(*Creator)(int); }; /// specializations can define other creators, this one requires an int, a /// bool, and a char template<> class Factory<InterfaceC> { public: typedef InterfaceC*(*Creator)(int,bool,char); }; |
Cool. Now we create a static interface that enforces it’s derivative classes to contain a static method called createNew
which can be used to instantiate a new object of that interface. We can use the typedef we just created to make the function signature generic for this template (or specific to individual instantiations of it).
39 40 41 42 43 44 45 46 47 48 | template<typename InterfaceType, typename ClassType> class IStaticFactory { public: IStaticFactory() { typename Factory<InterfaceType>::Creator check = ClassType::createNew; check = check; } }; |
Still following? Good. Now we define the registry class template, which maps the class name of a derived class to a function pointer with an interface-specific signature that serves as a static factory for objects of the derived class, returning a pointer to that object of the type of the interface. See my previous post for details on this class.
49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 | template <typename InterfaceType> class Registry { private: std::map< std::string, typename Factory<InterfaceType>::Creator > m_creatorMap; Registry(){} public: static Registry& getInstance(); bool registerClass( const std::string& name, typename Factory<InterfaceType>::Creator creator ); std::set<std::string> getClassNames(); typename Factory<InterfaceType>::Creator Registry<InterfaceType>::getCreator( std::string className ); }; // A convient macro to compact the registration of a class #define RegisterWithInterface( CLASS, INTERFACE ) namespace { bool dummy_ ## CLASS = Registry<INTERFACE>::getInstance().registerClass( #CLASS, CLASS::createNew ); } template <typename InterfaceType > Registry<InterfaceType>& Registry<InterfaceType>::getInstance() { static Registry<InterfaceType> registry; return registry; } template <typename InterfaceType > bool Registry<InterfaceType>::registerClass( const std::string& name, typename Factory<InterfaceType>::Creator creator ) { m_creatorMap[name] = creator; return true; } template <typename InterfaceType > std::set<std::string> Registry<InterfaceType>::getClassNames() { std::set<std::string> keys; typename std::map< std::string, InterfaceType* (*)(void) >::iterator pair; for( pair = m_creatorMap.begin(); pair != m_creatorMap.end(); pair++) keys.insert( pair->first ); return keys; } template <typename InterfaceType > typename Factory<InterfaceType>::Creator Registry<InterfaceType>::getCreator( std::string className ) { return m_creatorMap[className]; } |
The difference between this and the Registry in my previous post, is that this time the registry uses the generic Factory<InterfaceType>::Creator
typedef to define the function pointer. This way, that pointer is forced to have the specific signature. Sweet!
Now lets write some derived classes of those interfaces.
161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 | class DerivedA : public InterfaceA, public IStaticFactory<InterfaceA, DerivedA> { public: static InterfaceA* createNew(){ return (InterfaceA*)1; } }; RegisterWithInterface(DerivedA, InterfaceA); class DerivedB : public InterfaceB, public IStaticFactory<InterfaceB, DerivedB> { public: static InterfaceB* createNew(int a){ return (InterfaceB*)2; } }; RegisterWithInterface(DerivedB, InterfaceB); class DerivedC : public InterfaceC, public IStaticFactory<InterfaceC, DerivedC> { public: static InterfaceC* createNew(int a, bool b, char c){ return (InterfaceC*)3; } }; RegisterWithInterface(DerivedC, InterfaceC); |
These classes are basically dummies, but inheriting from IStaticFactory...
the compiler will enforce that they contain the static method createNew
with the proper signature. Notice that InterfaceA
uses the default template so the static factory in DerivedA
takes no parameters, while InterfaceB
and InterfaceC
have specializations so the static factories in DerivedB
and DerivedC
have their respective parameters. Since this is just an example, the methods don’t actually create new objects they just return pointers, but in reality this is where we would use new DerivedA(...)
and so on.
Well that’s it. Pretty cool huh? The compiler will enforce all this stuff for us so we can actually say to ourselves when we write new implementations months from now “If it compiles, it will be compatible.”
Lastly, here’s a little test case to run
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 | int main() { DerivedA a; DerivedB b; DerivedC c; InterfaceA* pA; InterfaceB* pB; InterfaceC* pC; Factory<InterfaceA>::Creator makesObjectOfA = Registry<InterfaceA>::getInstance().getCreator("DerivedA"); pA = (*makesObjectOfA)(); Factory<InterfaceB>::Creator makesObjectOfB = Registry<InterfaceB>::getInstance().getCreator("DerivedB"); pB = (*makesObjectOfB)(1); Factory<InterfaceC>::Creator makesObjectOfC = Registry<InterfaceC>::getInstance().getCreator("DerivedC"); pC = (*makesObjectOfC)(1,false,'a'); cout << "pA: " << pA << "n"; cout << "pB: " << pB << "n"; cout << "pC: " << pC << "n"; return 0; } |
Static Interfaces in C++
Posted by cheshirekow in C++ Discoveries and Notes, Programming on August 13, 2009
I remember looking around a few weeks ago for how to make a “static interface” in c++. Basically, I wanted a way to use the compiler to enforce that a class had certain static functions. Almost all of the internet resources I found basically said “Why would you ever want to do that; you don’t really want to do that; you probably have bad design” and so on… continuously begging the question. Of course, they were right: the design was bad and that wasn’t really what I wanted to do. Well, never the less, I still managed to think of a way to create a sort of static interface using a template class.
The strategy is to define a template class that uses the static methods of the template parameter class. That way, as long as the template is instantiated, the compiler will complain unless we have provided those static functions. We can ensure that the template is instantiated and enforce the inheritance idea by making the derived class extend from the template class we wrote to enforce those static methods.
Here is an example. We can create the static interface by declaring a class template that uses the functions we want to enforce as part of the interface.
1 2 3 4 5 6 7 8 9 10 | template < typename T > class StaticInterface { public: StaticInterface() { int(*fooCheck)(int) = T::foo; bool(*barCheck)(bool) = T::bar; } }; |
By assigning T::foo
and T::bar
to function pointers, we are saying, implicitly, that whatever class is provided as a parameter to this template must have a static method called foo
and a static method called bar
and, furthermore, that those static methods must have
the same signature as the function pointers we stuff them into.
By putting this code inside the constructor of the class, we know that this method of the template will be instantiated, even if we don’t explicitly use it later in the code, as long as we derive from this class somewhere. So then, the last question is, where can we derive from it?
Well, in the class that we want to inherit the interface of course!
11 12 13 14 15 16 | class DerivedClass : public StaticInterface<DerivedClass> { public: static int foo(int param){ return 10; } static bool bar(bool param){ return 20; } }; |
The DerivedClass
constructor implicitly calls the StaticInterface
constructor, which assigns the function pointers fooCheck
and barCheck
to the address of the functions DerivedClass::foo
and DerivedClass::bar
. As a result, if we forget the bar
function in the DerivedClass
the compiler will choke with an error. g++ says the following:
src/poc/test/StaticInterfaceTest.cpp: In constructor `StaticInterface
src/poc/test/StaticInterfaceTest.cpp:41: instantiated from here
src/poc/test/StaticInterfaceTest.cpp:20: error: `bar' is not a member of `DerivedClass'
Pretty cool huh?
As a final note, please consider this “an interesting observation” and not necessarily a “great design choice”. As I said, I decided against actually trying to utilize this idea in my project, and I urge you think carefully before about yours before trying to use it yourself.
Keep Track of and Enumerate All Sub-classes of a Particular Interface
Posted by cheshirekow in C++ Discoveries and Notes, Programming on August 11, 2009
Here’s another interesting C++ problem I encountered today. As is often the case, I found my answer by asking over at Stack Overflow. The question can be found here: http://stackoverflow.com/questions/1260954/how-can-i-keep-track-of-enumerate-all-classes-that-implement-an-interface
The issue was that I was writing a simulation program where I knew I would eventually want to simulate multiple different vehicles, with multiple different controllers, and multiple different estimators. Naturally, this led me to define an interface for each of these things, but the problem was that I only really want to implement a few subclasses of these interfaces now. In particular, I only have two vehicles, 2 controllers, and 1 estimator I’m interested in completing now, but I will probably want to implement at least 2 more vehicles, 2 more controllers, and 2 or 3 more estimators. And, finally, as far as the simulation is designed, I would like for the user to be able to select from a list of choices which vehicle, which controller, and which estimator to use. Therefore, I was looking for a clean way to keep a kind of registry of classes that implement each of these interfaces so that I wouldn’t have to go back and change the interface code later when I implemented more sub-classes.
The solution that was accepted was to implement a registry class that maintains a mapping of class-names to constructors, and then update that mapping from within the class definition file from each of the implementing sub-classes using a static initializer. I went one step further and made the registry class generic (templated), and this is the result. There is an example code below.
File: CInterfaceRegistry.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 | /** * file CInterfaceRegistry.h * date: Aug 11, 2009 * brief: * * detail: */ #ifndef CINTERFACEREGISTRY_H_ #define CINTERFACEREGISTRY_H_ #include <map> #include <string> #include <set> #include <typeinfo> #include "exception/IllegalArgumentException.h" namespace utility { /** * brief Generic singleton object to maintains a registry of subclasses * that implement a particular interface * * This clever solution was taken from the discussion at the following site: * http://stackoverflow.com/questions/1260954/how-can-i-enumerate-all- * classes-that-implement-an-interface * * note: The registry will allow the registration of any class that extends * an interface so long as it has a factory method, but the * RegisterWithInterface macro will only work with classes that have * named that method create() * * */ template <typename InterfaceType> class CInterfaceRegistry { private: std::map< std::string, InterfaceType* (*)(void) > m_creatorMap; /** * brief private to ensure that only the singleton ( the single * static instantiation ) of this template class is used */ CInterfaceRegistry(){} public: /** * brief returns the registry instance particular to the specified * interface (specified as template parameter) */ static CInterfaceRegistry& getInstance(); /** * brief registers a new subclass of a an interface */ bool registerClass( const std::string& name, InterfaceType* (*creator)(void) ); /** * brief registers a new subclass from it's typeid() result, rather * than from a hand-typed class name */ bool registerClass( const std::type_info& classType, InterfaceType* (*creator)(void) ); /** * brief returns a list of classes registered with this interface */ std::set<std::string> getClassNames(); /** * brief returns a new object of the specified class */ InterfaceType* createObjectOf( std::string className ); }; // A convient macro to compact the registration of a class #define RegisterWithInterface( CLASS, INTERFACE ) namespace { bool dummy_ ## CLASS = CInterfaceRegistry<INTERFACE>::getInstance().registerClass( typeid(CLASS), CLASS::create ); } /** * The use of this method ensures that this template class remains singleton. * Only the static registry object created by this method will exist for any * instantiation of this class. */ template <typename InterfaceType > CInterfaceRegistry<InterfaceType>& CInterfaceRegistry<InterfaceType>::getInstance() { static CInterfaceRegistry<InterfaceType> registry; return registry; } /** * To register a class with this registry, we map a factory function that is * capable of generating objects of the class and returning a pointer of the * interface type. The key we map it to is the name of the class. */ template <typename InterfaceType > bool CInterfaceRegistry<InterfaceType>::registerClass( const std::string& name, InterfaceType* (*creator)(void) ) { m_creatorMap[name] = creator; return true; } /** * For added convenience, we can avoid typing the class names by hand if we * use the typeid() operator. This method will extract the class name from * a type_info class and pass it on to the actual registration method. */ template <typename InterfaceType > bool CInterfaceRegistry<InterfaceType>::registerClass( const std::type_info& classType, InterfaceType* (*creator)(void) ) { return registerClass( std::string(classType.name()), creator ); } /** * To generate a list of the class names currently registered with this * interface, we iterate through the map and extract all the keys. */ template <typename InterfaceType > std::set<std::string> CInterfaceRegistry<InterfaceType>::getClassNames() { std::set<std::string> keys; typename std::map< std::string, InterfaceType* (*)(void) >::iterator pair; for( pair = m_creatorMap.begin(); pair != m_creatorMap.end(); pair++) keys.insert( pair->first ); return keys; } /** * To create a new object of the specified class, we simply de-reference the * stored factory method and execute it. */ template <typename InterfaceType > InterfaceType* CInterfaceRegistry<InterfaceType>::createObjectOf( std::string className ) { InterfaceType* (*creator)(void) = m_creatorMap[className]; if(creator) return *creator(); else throw IllegalArgumentException( className + "is not registered with the registry"); } } #endif /* CINTERFACEREGISTRY_H_ */ |
File: CInterfaceRegistryTest.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | /** * file CInterfaceRegistryTest.cpp * date: Aug 11, 2009 * brief: * * detail: */ #include "utility/CInterfaceRegistry.h" #include <iostream> #include <map> #include <set> using namespace utility; using std::map; using std::set; using std::cout; using std::string; // create the interface that we will be extending class IDummyInterface{}; // create the first of several implementations of that interface class CDerivedA : public IDummyInterface { public: // the class must have some kind of static factory method static IDummyInterface* create(){ return new CDerivedA(); } }; // and this is how we register the class with the registry bool dummyA = CInterfaceRegistry<IDummyInterface>::getInstance().registerClass( "CDerivedA", CDerivedA::create ); // we create, here, the second of several implementations, it's basically the // same as the first class CDerivedB : public IDummyInterface { public: // again with the static factory method static IDummyInterface* create(){ return new CDerivedB(); } }; // this is the same as above bool dummyB = CInterfaceRegistry<IDummyInterface>::getInstance().registerClass( "CDerivedB", CDerivedB::create ); // and a nother implementation class CDerivedC : public IDummyInterface { public: // ditto... static IDummyInterface* create(){ return new CDerivedC(); } }; // this time we use that convenient macro that does things a little more // compactly and, I think, without sacrificing readabilty RegisterWithInterface( CDerivedC, IDummyInterface ); int main() { // here we can retrieve a list of all the registered classes by // querying the registry object set<string> classes = CInterfaceRegistry<IDummyInterface>::getInstance().getClassNames(); cout << "Currently registered subclasses of IDummyInterface: n"; cout << "-- --------------------nn"; set<string>::iterator str; for( str = classes.begin(); str != classes.end(); str++ ) cout << *str << "n"; cout << "nndonen"; return 0; } |
Note that the name returned by querying typeid()
has a “9” inserted in the front of it. The names used to identify a type in the type_info
class are implementation specific, so it may or may not be a good idea to use them. In my case it will be fine.
Edit:
A better choice for the macro is to use something like this
1 2 3 4 5 6 7 8 | // A convient macro to compact the registration of a class #define RegisterWithInterface( CLASS, INTERFACE ) namespace { bool dummy_ ## CLASS = Registry<INTERFACE>::getInstance().registerClass( #CLASS, CLASS::createNew ); } |
which uses the class’s name from the source code instead of the type_info
name.