Reputation: 13993
Let's say I have 100 classes derived from Base. Each of these Derived classes has a unique identifier between [0,100), known at compile time.
I have a function that takes an ID and needs to return a newly allocated instance of the derived class with that ID.
Base* CreateDerived(uint32_t id) {
return new Derived...();
}
It's evidently not a good solution to have a huge switch case for each ID. An example of the best solution I can come up with is provided below, but I feel like there is a way to do this without the overhead introduced by the vtable.
struct RegisteredClass {
static RegisteredClass* ClassTable[MAX_DERIVED_CLASSES];
static Base* CreateDerived(int ID) { return ClassTable[ID]->Create(); }
RegisteredClass(int ID) { ClassTable[ID] = this; }
virtual Base* Create() = 0;
};
template<typename T, int ID>
struct Register : RegisteredClass {
Register() : RegisteredClass(ID) { }
virtual Base* Create() { return new T; }
};
class Derived34 : Base {
static Register<Derived34, 34> _register;
};
Am I being silly, or is there another approach to this that doesn't require so much space?
Upvotes: 3
Views: 132
Reputation: 308382
Here's a situation where the old crusty macro capability can simplify the task and eliminate some errors.
#define CASE(n) case n: return new Derived##n
Base* CreateDerived(uint32_t id)
{
switch(id)
{
CASE(1);
CASE(2);
CASE(3);
// ...
default:
throw std::logic_error("Unhandled Derived## case");
}
}
#undef CASE
Upvotes: 0
Reputation: 258618
It's evidently not a good solution to have a huge switch case for each ID.
That's actually the abstract factory pattern, and it's widely used just as you described it. I would stick to it, as it's familiar to most programmers.
Your variant seems overly-complicated and hard to maintain.
Upvotes: 1