Class Factory

A while back I made a class factory by doing the following:
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
class A
{

};

A * classASpawner()
{
    return new A;
}

class B : public A
{

};

A* classBSpawner()
{
    return new B;
}

std::unordered_map <std::string, A* (*spawner)()> factory;

void registerSpawner(std::string className, A* (*spawner)())
{
    factory[className] = spawner;
}

/// Somewhere else while loading from a text file
A* loadFile(std::string filePath)
{
    std::ifstream ifile(filePath.c_str());
    while(good)
    {
        std::string className;
        ifile >> className;
        myVector.push_back(factory[className]());
        // now the myVector is being loaded with both A's and B's without
        // really caring which is which. Polymorphism taking care of that.

        // Of course this requires parsing and reading in the data for each object too, but
        // this was the basic idea.
    }
}


- Sorry, that's all typed in-place, not meant to run as-is.
So is there a way to register a class constructor and cut out the man in the middle spawner function?
Is there a better way to create an object from a file?
Last edited on
I think I've found a good answer using templates, the functional header, and a lambda:
https://codereview.stackexchange.com/questions/114578/simple-factory-retrieving-object-by-name

I don't have a solid understanding of templates, and I've never looked into the functional header, so it's time for me to hit the books.
Last edited on
Here's a working example, similar to what is found in the stack overflow link, but it proves to me how easy this will be to plug into my much larger code base;
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
// Create a factory that takes a string, outputs a new item without a spawner function as a middleman

#include <unordered_map>
#include <functional>
#include <iostream>

class base
{
	public:
	base();
	int val;
};

base::base()
{
	std::cout << "Base type created.\n";
	val = 1;
}

class child : public base
{
	public:
	child();

};

child::child()
{
	std::cout << "Child type created.\n";
}

std::unordered_map <std::string, std::function<base*()> > types;

template <typename T> void registerType(std::string type)
{
	types[type] = []()
	{ 
		return new T;
	};
}

base * getObj(std::string type)
{
	return types[type]();
}

int main()
{
	registerType<base>("base");
	registerType<child>("child");

	base * t1 = getObj("base");
	base * t2 = getObj("child");

	delete t1;
	delete t2;
}
Last edited on
Your last post doesn't need the stuff in functional. A plain function pointer will still work just fine. You just have to specify the anonymous function's return type.

1
2
3
4
5
6
7
8
9
std::unordered_map <std::string, base*(*)()> types;

template <typename T> void registerType(std::string type)
{
	types[type] = []() -> base*
	{ 
		return new T;
	};
}
Last edited on
Thank you Mbozzi!
That just cut out a good chunk of the noise.
Last edited on
Interesting way to create objects. May I ask you why you don't use simply
1
2
base* t1 = new base();
child* t2 = new child(); 

I guess that there is something behind this alternative and I would like to know what. Thanks ++
Last edited on
May I ask you why you don't use simply

Class Factory.

https://stackoverflow.com/questions/2526879/what-exactly-is-a-class-factory

More "linkages" at this DDG meta-search:

https://duckduckgo.com/?q=c%2B%2B+what+is+a+class+factory&t=ffsb&ia=web
Sorry, took a break from the internet for a bit.

The key use that I get out of the "factory method" is that I can save the details of an object in an XML file (human readable/editable text data file). Now my objects can be modified by data files rather than everything being hard-coded. If I want to add a new goblin in the top left corner of a board I now just add a single line in the xml data file and the changes are made without even having to recompile the program.

The reason that the template is so important is that this is for a system of dynamically loaded object files, so I can't know every class type available until the plugin file registers it. Instead of each plugin needing to create a similar function, the plugin just needs to call registerType in order to use the functionality on classes that it wants to be able to load.

<goblin height="100" width="70" x="1050" y="30" attack="12" def="6"><image src="res/images/goblin.png"></goblin>

As long as "goblin" has been registered by the plugin, I can call getObj("goblin") and load the rest of the data into the new goblin object as I parse the attributes.
Last edited on
Topic archived. No new replies allowed.