c++ - Best way to instantiate different object types according to value? -
i'll simplify problem of hundreds of classes count of 2 , try explain mean:
class base { }; class a: public base { }; class b: public base{ }; static base* foo (int bar){ switch (bar) { case 0: return new a(); break; case 1: return new b(); break; default: return new base(); } }
i want instantiate objects according value of bar. feel switch-case isn't best way in c++ way more inheritors of base
.
edit: going std::map
approach came this:
struct dictionary { typedef base* (dictionary::*functionpointer)(void); std::map <int, functionpointer> fmap; dictionary() { fmap.insert(std::make_pair(0, new a())); fmap.insert(std::make_pair(1, new b())); } base* call (const int i){ functionpointer fp = null; fp = fmap[i]; if (fp){ return (this->*fp)(); } else { return new base(); } } }; static dictionary dictionary;
a lot depends on circumstances, frequent solution use static instance of map factory functions. if key type of map small integer value, in example, "map" can nothing more c style array:
static base* foo( int bar ) { static base* (*factories[])() = [ &afactory, &bfactory ]; return bar >= 0 && bar < size( factories ) ? (*factories[bar])() : basefactory(); }
more generally, can use std::map
(to discriminate on imaginable type), , can map static instances of factory objects, rather factory functions, if different keys should result in same type, different arguments.
edit:
some suggestions improve dictionary::call
function:
base* dictionary::call( int ) const { std::map<int, functionpointer>::const_iterator entry = fmap.find( ); return entry == fmap.end() ? new base() : (this->*(entry->second))(); }
i've made function const
, since doesn't modify anything, , impprtantly, use std::map<>::find
, avoid inserting entries map if object isn't there.
and since i'm adding const, you'll have update typedef:
typedef base* (dictionary::*functionpointer)() const;
another suggestion: unless factory functions need access dictionary
, make them static. syntax lot simpler (and improve performance). static changes typedef again:
also: in constructor, new a()
not function constructing new object. there may facilitate in c++11 (between lambda , std::function
), otherwise, you'll still have write each of factory functions hand. or use template:
template <typename target> base* construct() const { return new target(); } dictionary() { fmap.insert( std::make_pair( 0, &dictionary::construct<a> ) ); // ... }
or if make them static:
typedef base* (*functionpointer)(); // ... template <typename target> static base* construct() { return new target(); } base* dictionary::call( int ) const { std::map<int, functionpointer>::const_iterator entry = fmap.find( ); return entry == fmap.end() ? new base() : (*entry->second)(); }
you'll notice how static simplifies declarations (and function call through pointer—your pointer member function has become simple pointer function).
Comments
Post a Comment