Class Factory

Oct 16, 2022 at 12:36am
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 Oct 16, 2022 at 12:45am
Oct 16, 2022 at 3:29am
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 Oct 16, 2022 at 3:29am
Oct 16, 2022 at 4:20am
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 Oct 16, 2022 at 4:21am
Oct 16, 2022 at 4:49am
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 Oct 16, 2022 at 4:49am
Oct 16, 2022 at 6:30am
Thank you Mbozzi!
That just cut out a good chunk of the noise.
Last edited on Oct 16, 2022 at 6:33am
Oct 17, 2022 at 1:43pm
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 Oct 17, 2022 at 1:44pm
Oct 17, 2022 at 6:12pm
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
Oct 24, 2022 at 6:43am
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 Oct 24, 2022 at 6:47am
Topic archived. No new replies allowed.