Typically this is achieved through some form of dynamic type information, be it using templates + typeid() or some other form of unique type identification
The basic idea consists of two classes. A "Manager" and a "Factory". The manager stores a collection of factories and associated type identification, and the factories know how to instantiate the type you need.
The following is a complete example using std::type_info. Note that you will need C++11 because of hash_code(). If you must use c++03 then you can replace hash_code() with name() and run that through your own hash function (or change the type in the container from size_t to std::string).
#include <typeinfo>
#include <map>
#include <string>
#include <iostream>
class Factory {
public:
virtual void* Create() = 0;
};
template <class T>
class FactoryImpl : public Factory
{
virtual void* Create() override
{
return new T();
}
};
class Manager
{
public:
template <class T>
void RegisterObjectFactory()
{
factoryMap_[typeid(T).hash_code()] = new FactoryImpl<T>();
}
template <class T>
T* CreateObject() const
{
auto factory = factoryMap_.find(typeid(T).hash_code());
if(factory == factoryMap_.end())
return NULL;
return static_cast<T*>(factory->second->Create());
}
template <class T>
void DestroyObject(T* object)
{
delete object;
}
private:
std::map<size_t, Factory*> factoryMap_;
};
// ----------------------------------------------------------------------------
// Example usage
// ----------------------------------------------------------------------------
class Test
{
public:
void Greet() { std::cout << "it works!" << std::endl; }
};
int main()
{
Manager manager;
manager.RegisterObjectFactory<Test>();
Test* test = manager.CreateObject<Test>();
test->Greet();
manager.DestroyObject(test);
}
One pitfall to look out for with factories is to make sure you delete the object in the same DLL you created it. This is why Manager::DestroyObject() is necessary. If you were to convert it from raw pointers to std::shared_ptr then this would no longer be necessary to do.
With this method you would need to pass the manager instance to your plugin DLLs when they start (typically achieved by defining your own start_plugin() function). Then your plugins can call Manager::RegisterObjectFactory<Whatever>() to register the types they require. This will enable the core application to start instantiating types that weren't originally there when compiling.
You might consider extending the example to make it possible to pass the actual class name to the manager, and not just the has code. For example:
manager.CreateObject("Test");
instead of
manager.CreateObject<Test>();
For this you would need to store typeid(T).name() in the corresponding factory class.
"I would try to find halo source code by bungie best fps engine ever created, u see why call of duty loses speed due to its detail." -- GettingNifty