Reputation: 4057
sorry for the title, it's quite confusing to explain, but it will be more clear with example
In C, I used to write program like this :
void createClassA()
{
}
void createClassB()
{
}
typedef struct {
const char *name;
void (*create_class)();
} MapList;
MapList mapList[] = {
{"A", &createClassA},
{"B", &createClassB },
};
void create(const char *name)
{
int i=0;
for (i=0; i < sizeof(mapList) / sizeof(MapList); i++) {
if (strcmp(name, mapList[i].name) == 0) mapList[i].create_class();
}
}
int main(int argc, char** argv)
{
if (argc < 1) return -1;
create(argv[1]);
return 0;
}
So if I have more types, all I have to do is to create the function itself and add it to the mapList.
but in C++, the best I can do is something like:
#include <iostream>
class myA{};
class myB{};
class myC{};
class Base
{
public:
template<class T>
void createClass()
{
T* t = new T();
//t->doSomethingUseful();
}
void create(const std::string name)
{
if (name=="A") createClass<myA>();
else if (name=="B") createClass<myB>();
else if (name=="C") createClass<myC>();
}
};
int main(int agrc, char** argv)
{
if (argc<1) return -1;
Base b;
b.create(argv[0]);
return 0;
}
Can I create something like :
typedef struct {
std::string name;
[CLASS_TYPE] class_type; <== I don't know how
} MapList;
so I can create a mapping List but fill it with class Type, something like
mapList[] = {
{"A", myA},
{"B", myB},
{"B", myC},
};
and then I can create iteration like:
for (int i=0; i<sizeof(mapList) / sizeof(MapList); i++) {
if (mapList[i].name == name) b.createClass<mapList[i].classType>();
}
Thanks guys :)
Upvotes: 0
Views: 95
Reputation: 76240
In C++ you can use std::function
in the <functional>
standard header. Specifically, your example for the map list can be written as (with lambdas):
std::map<std::string, std::function<void()>> mapList;
mapList["A"] = []() { /* ... */ };
mapList["B"] = []() { /* ... */ };
or just (without lambdas):
void createClassA() {}
void createClassB() {}
std::map<std::string, std::function<void()>> mapList;
mapList["A"] = createClassA;
mapList["B"] = createClassB;
Upvotes: 2
Reputation: 5345
You can use derived classes and object factory, something like that would work. You can improve it by make create method to return smart pointers and make A and B constructors private to avoid creating objects on the stack.
class Base
{
static Base* create(const char *name);
};
class A : public Base
{
};
class B : public Base
{
};
Base* Base::create(const char *name)
{
if(strcmp(name,"A")==0)
return new A();
if(strcmp(name,"B")==0)
return new B();
return 0;
}
int main(int agrc, char** argv)
{
if (argc<1) return -1;
Base *b = Base::create(argv[0]);
return 0;
}
It is somewhat similar to solution by @dasblinkenlight, but avoid virtual functions overhead.
Upvotes: 0
Reputation: 726579
In C++ you could do that with virtual functions:
struct ClassMaker {
virtual void create_class() = 0;
};
struct ClassMakerA : public ClassMaker {
virtual void create_class() {
...
}
};
struct ClassMakerB : public ClassMaker {
virtual void create_class() {
...
}
};
Now you can create a std::map<std::string,ClassMaker*>
with your "factories", like this:
ClassMakerA makerA;
ClassMakerB makerB;
// This syntax requires C++11
std::map<std::string,ClassMaker*> makers = {
{"A", &makerA}
, {"B", &makerB}
};
Finally, you can now call create_class()
based on a std::string
value, like this:
void create(const std::string &name) {
ClassMaker *maker = makers[name];
if (maker) maker -> create_class();
}
Upvotes: 1
Reputation: 12907
You could look for Boost::any
, which provides "a variant value type".
Upvotes: 0