Best way to create instances of different types of objects according to cost?

I will simplify my problem of hundreds of classes by two and try to explain what I 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 to create objects according to the value of bar. I just find that a switch is not the best way in C ++ to do this for more Base .

Edit: Going to the std::map approach, I came up with the following:

 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; 
+6
source share
1 answer

Much depends on the circumstances, but most often the solution is probably to use a static map instance for the factory. If the key type of map is a small integer value, as in your example, a "map" can be nothing more than an array of C styles:

 static Base* foo( int bar ) { static Base* (*factories[])() = [ &aFactory, &bFactory ]; return bar >= 0 && bar < size( factories ) ? (*factories[bar])() : baseFactory(); } 

More generally, you can use std::map (for any conceivable type), and you can map static instances of factory, not factory functions, if different keys should lead to the same type, but with different arguments.

EDIT:

Some suggestions for improving the Dictionary::Call function:

 Base* Dictionary::Call( int i ) const { std::map<int, FunctionPointer>::const_iterator entry = fmap.find( i ); return entry == fmap.end() ? new Base() : (this->*(entry->second))(); } 

I made the const function, since it does not change anything, and most imperceptibly, I use std::map<>::find so as not to insert extra entries into the map if the object is not already there.

And since I am adding const, you will need to update LurieE:

 typedef Base* (Dictionary::*FunctionPointer)() const; 

Another suggestion: if the factory functions do not need Dictionary access, make them static. The syntax is much simpler (and this will probably also improve performance). static changes typedef again:

Also: in the constructor new A() not a function to build a new object. Maybe something make this easier in C ++ 11 (between lambda and std::function ), but otherwise you still have to write each of the factory functions manually. Or you can use the template:

 template <typename Target> Base* construct() const { return new Target(); } Dictionary() { fmap.insert( std::make_pair( 0, &Dictionary::construct<A> ) ); // ... } 

Or, if you make them static:

 typedef Base* (*FunctionPointer)(); // ... template <typename Target> static Base* construct() { return new Target(); } Base* Dictionary::Call( int i ) const { std::map<int, FunctionPointer>::const_iterator entry = fmap.find( i ); return entry == fmap.end() ? new Base() : (*entry->second)(); } 

You will notice how static simplifies declarations (and calling a function through a pointer - a pointer to a member function has become a simple pointer to a function).

+2
source

Source: https://habr.com/ru/post/944854/


All Articles