You're describing a factory function. There are many ways to accomplish this, from registries to simple if/else
chains.
Usually your Image
class derives from a similar base class to other "parsed in" types. That way, you can add them all to the same container.
Imagine this hierarchy:
class Media {
public:
virtual Save() = 0;
};
class Image : public Media {
public:
Image() { }
virtual Save() { ... }
};
class Sound : public Media {
public:
Sound() { }
virtual Save() { ... }
};
The simplest construct is a factory function:
Media *CreateMedia(const string &type) {
if (type == "Image") {
return new Image;
} else if (type == "Sound") {
return new Sound;
} else {
// handle invalid type error
}
}
Another alternative is to use a registry, instead of CreateMedia
you would usually use a macro, a factory/registry and some mechanism to create your subclasses:
// This is some mechanism to create types of Media.
template <typename T>
struct CreatorFunction {
Media *operator() {
return new T;
}
};
// This is the factory that the types will register with.
class Factory {
public:
// singleton access function.
static Factory* Get() {
static Factory* f = new Factory;
return f;
}
// Creates Media of the given type.
Media* Create(const string& name) { return registry_[name](); }
// Records 'name' with the creator function 'func'.
void Add(const string& name, const CreatorFunction &func) {
registry_.insert(name, func);
}
private:
Factory() { } // users can't create factories, they can only use singleton.
hash_map<string, CreatorFunction> registry_;
};
#define REGISTER_MEDIA(type) Factory::Get()->Add(#Image, CreatorFunction<type>);
REGISTER_MEDIA(Image); // usually goes with the Image class.
REGISTER_MEDIA(Sound); // usually goes with the Sound class.
int main(int argc, char** argv) {
string parsedIn = "Image";
Factory::Get()->Create(parsedIn);
}
This is a cleaner approach overall, but you may have problems with your linker thinking some symbols are unused and trimming the important registered classes out of your binary. You'll probably want to stick with the if/then
chaining until you need something more sophisticated. You usually go for registries once it's infeasible to have a single location where all subtypes are defined.