Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p><strong>Update</strong>: This answer made the assumption that some kind of <a href="https://en.wikipedia.org/wiki/File_format#Magic_number" rel="nofollow">magic</a> existed that could be read and passed to the factory, but that's apparently not the case. I'm leaving the answer here because a) I may update it, and b) I like it anyway.</p> <hr> <p>Not hugely different from your own answer, not using C++11 techniques (I've not had a chance to update it yet, or have it return a smart pointer, etc), and not entirely my own work, but this is the factory class I use. Importantly (IMHO) it doesn't call each possible class's methods to find the one that matches - it does this via the map.</p> <pre><code>#include &lt;map&gt; // extraneous code has been removed, such as empty constructors, ... template &lt;typename _Key, typename _Base, typename _Pred = std::less&lt;_Key&gt; &gt; class Factory { public: typedef _Base* (*CreatorFunction) (void); typedef std::map&lt;_Key, CreatorFunction, _Pred&gt; _mapFactory; // called statically by all classes that can be created static _Key Register(_Key idKey, CreatorFunction classCreator) { get_mapFactory()-&gt;insert(std::pair&lt;_Key, CreatorFunction&gt;(idKey, classCreator)); return idKey; } // Tries to create instance based on the key static _Base* Create(_Key idKey) { _mapFactory::iterator it = get_mapFactory()-&gt;find(idKey); if (it != get_mapFactory()-&gt;end()) { if (it-&gt;second) { return it-&gt;second(); } } return 0; } protected: static _mapFactory * get_mapFactory() { static _mapFactory m_sMapFactory; return &amp;m_sMapFactory; } }; </code></pre> <p>To use this you just declare the base-type, and for each class you register it as a static. Note that when you register, the key is returned, so I tend to add this as a member of the class, but it's not necessary, just neat :) ...</p> <pre><code>// shape.h // extraneous code has been removed, such as empty constructors, ... // we also don't technically need the id() method, but it could be handy // if at a later point you wish to query the type. class Shape { public: virtual std::string id() const = 0; }; typedef Factory&lt;std::string, Shape&gt; TShapeFactory; </code></pre> <p>Now we can create a new derived class, and register it as creatable by <code>TShapeFactory</code>...</p> <pre><code>// cube.h // extraneous code has been removed, such as empty constructors, ... class Cube : public Shape { protected: static const std::string _id; public: static Shape* Create() {return new Cube;} virtual std::string id() const {return _id;}; }; // cube.cpp const std::string Cube::_id = TShapeFactory::Register("cube", Cube::Create); </code></pre> <p>Then we can create a new item based on, in this case, a string:</p> <pre><code>Shape* a_cube = TShapeFactory::Create("cube"); Shape* a_triangle = TShapeFactory::Create("triangle"); // a_triangle is a null pointer, as we've not registered a "triangle" </code></pre> <p>The advantage of this method is that if you create a new derived, factory-generatable class, you don't need to change any other code, providing you can see the factory class and derive from the base:</p> <pre><code>// sphere.h // extraneous code has been removed, such as empty constructors, ... class Sphere : public Shape { protected: static const std::string _id; public: static Shape* Create() {return new Sphere;} virtual std::string id() const {return _id;}; }; // sphere.cpp const std::string Sphere::_id = TShapeFactory::Register("sphere", Sphere::Create); </code></pre> <p>Possible improvements that I'll leave to the reader include adding things like: <code>typedef _Base base_class</code> to <code>Factory</code>, so that when you've declared your custom factory, you can make your classes derive from <code>TShapeFactory::base_class</code>, and so on. The Factory should probably also check if a key already exists, but again... it's left as an exercise.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload