templated abstract factory class with pooling - c++

I'm working on a game engine component that handles events. What I'm trying to do is create a system that I can register new event types by name. The event manager will then hold a collection of event types and the factories to generate such an event type BUT the twist is that I want to make it used a pooling system such that I create an event, use it and then rather than deleting it, throw it into a list. Next time I create that event, rather than using the heap, I can just allocate from the pool.
SO given these hierarchy of event types...
struct TEvent
{
int nID;
int nTimeStamp;
};
struct TCollisionEvent : public TEvent
{
TEntity* pEntity1;
TEntity* pEntity2;
Vector3* pvecPoint;
};
I then created a smart factory which does this creation/recyling operation:
template <class BASE_CLASS>
class CSmartFactory
{
private:
typedef typename std::list<BASE_CLASS*> TBaseList;
typedef typename std::list<BASE_CLASS*>::iterator TBaseListItr;
TBaseList* m_plstPool;
public:
explicit CSmartFactory()
{
m_plstPool = NULL;
}
~CSmartFactory()
{
TBaseListItr itr;
if (m_plstPool)
{
for (itr = m_plstPool->begin(); itr != m_plstPool->end(); itr++)
{
BASE_CLASS* pEntity = *itr;
SAFE_DELETE(pEntity);
}
m_plstPool->clear();
SAFE_DELETE(m_plstPool);
}
}
bool Init(int nPoolSize)
{
bool bReturn = false;
do
{
m_plstPool = new TBaseList;
IwAssert(MAIN, m_plstPool);
while (nPoolSize--)
{
BASE_CLASS* pBaseObject = new BASE_CLASS;
IwAssert(MAIN, pBaseObject);
m_plstPool->push_back(pBaseObject);
}
bReturn = true;
} while(0);
return bReturn;
}
BASE_CLASS* Create()
{
BASE_CLASS* pBaseObject = NULL;
//
// grab a pre-made entity from the pool or allocate a new one
if (m_plstPool->size() > 0)
{
pBaseObject = m_plstPool->front();
m_plstPool->pop_front();
pBaseObject->Clear();
}
else
{
pBaseObject = new BASE_CLASS;
IwAssert(MAIN, pBaseObject);
}
return pBaseObject;
}
void Recycle(BASE_CLASS* pBaseObject)
{
m_plstPool->push_back(pBaseObject);
}
};
SO now I can do this:
CSmartFactory<TCollisionEvent>* pCollisionEventFactory = new CSmartFactory<TCollisionEvent>;
BUT what I want to do is have my event manager allow for dynamic event registration but that's where I run into my snag.
Ideally RegisterEvent will track the name and factory pointer in an stl::map or something but not quite sure how to get to that point. Maybe I've gone down the wrong path altogether.
This compiles
class TEventManager
{
public:
TEventManager();
~TEventManager();
bool RegisterEvent(char* pszEventName, CSmartFactory<TEvent>* pFactory);
};
Until you add
TEventManager::RegisterEvent("CollisionEvent", new CSmartFactory<TEntityCollisionEvent>);
So now I'm hopelessly trying to find a way to make this all work.
Anybody got some ideas here!?
Fred

I assume that you want to reuse events to avoid expensive heap malloc/free's?
I think the right answer here is not to convolute your code by writing your own structure for reusing objects, but to use a small-object allocator. As a start, it may be worth looking into boost::pool.

The two classes CSmartFactory<TEntityCollisionEvent> and CSmartFactory<TEvent> will be generated to something like
CSmartFactory_TEntityCollisionEvent
CSmartFactory_TEvent
They are actually two separate and unrelated classes. Trying to use them interchangeably would be unwise, although they behave the same (their type classes are polymorphic right).
Dynamic casting wont work, you could however try to use brute force casting:
TEventManager::RegisterEvent("CollisionEvent",
reinterpret_cast<CSmartFactory<TEvent>*>(new CSmartFactory<TEntityCollisionEvent>));
Warning: At your own risk! ;-)

OK so after a lot of head banging, I realized the solution is FAR simpler than what I was trying to pull off.
All the manager should care about is managing a TEvent*. Each TEvent has a unique hash value that makes it unique so when a new event is added both the string name and hash name of that even is stored. So from there I can add a pointer to any subclass so long as it's casted to TEvent.
I was making it FAR more complex than it needed to be.

Related

Implementing a component System for my 2d C++ game

I've been trying to figure out a way to implement a component system for my simple 2d fighting game where I can easily swap in new components returned from my system functions. The idea is I have a bunch of system functions which will work on a set of components:
example:
PosisiontComponent MovementSystem(PositionComponent pos, VelocityComponent vel)
{
//..Make entity move
return pos;
}
The key here is I want to return a new copy of the component, and not modify the state directly in within my system function (for easier comprehension and testing of systems). Ideally, this new updated position component can then be inserted in my Fighter (which acts basically like an entity class) through an myFighter.Insert() member function of some sort. So far, I'm thinking of using a std::map<int key, Component* comp> to store my components with the key being a unique id that is connected with only one component type which I can use to look up certain components within the map. The fighter class might look something like:
class Fighter
{
public:
void Insert(Component* comp);
Component* Get();
std::map<int, Component*> componentMap;
}
Fighter::Fighter(std::string const imageFilePath, float startPositionX, float startPositionY) :
sprite(imageFilePath, 200, 200)
{
componentMap[0] = new PositionComponent(glm::vec2{ 0.0f, 0.0f });
componentMap[1] = new VelocityComponent();
}
void Fighter::Insert(Component* component)
{
componentMap.erase(compID);
componentMap[compID)] = component;
}
Component* GetComponent()
{
return componentMap[id];
}
The problem I'm running into is I don't quite know how I would return individual components through a GetComponent() function (currently just getting compiler errors due to conversion of type problems) with the current implementation.
My question(s) are:
1.) Is my current implementation a viable solution? Is there a way to extract specific components from GetComponent() function without getting compiler issues? If not, whats a better way to easily swap out individual components inside my Fighter class?
Assuming each entity can only have one component per type, you could use templates.
template<typename T>
T* getComponent() {
for (auto &component : components)
{
T* derivedComponent = dynamic_cast<T*>(component);
if (derivedComponent)
{
return derivedComponent;
}
}
return NULL;
}
Then using it will be simple and it does not require an id to be shared around. Also the order of the map can be changed without breaking the game. This is would happen as you add and remove components at runtime.
Fighter* f;
PosisiontComponent* positionComponent = f->getComponent<PosisiontComponent>();
This is the approach I have used in the past and it has worked very nicely. However, I would recommend using smart pointers as opposed to raw pointers for these containers.

Correct way to store objects in another object in C++?

I have 3 object, let's call them Main, Manager & Item.
The Manager needs to have an array of Items. These Items are added to the Manager from the Main object.
I'd like to know how should I pass the Items to the Manager in order to make them live even outside the Main() function scope, but at the same time, being able to delete them when the Manager is destroyed.
NOTE
Item, inside Manager, have to be a pointer because I need to check for NULL items
So far I have something like this (not actual code for short):
Main
{
Manager* Man;
Main()
{
Man = new Manager(/**/); //i use a pointer because i need this object to persist;
Item* it = new Item(/**/);
Man->AddItem(it);
}
~Main()
{
delete(Man);
}
}
Manager
{
Item* ItemArchive[15];
void AddItem(Item* item)
{
ItemArchive[index] = item;
}
~Manager()
{
for(int i=0;i<archiveLength;i++)
delete(ItemArchive[i]); //Here i get a runtime error,most probably an
//access violation,can't be more specific
//because Unreal Engine doesn't give me that info
}
}
Item
{
//just a basic object
}
So my question is, how can I create the objects in the Main and then being able to use and delete them inside the Manager?
Consider using std::unique_ptr<Item> and pass ownership from Main to the Manager:
#include <vector>
#include <memory>
class Item {};
class Manager {
std::vector<std::unique_ptr<Item>> item_archive;
public:
void addItem(std::unique_ptr<Item> item){
item_archive.push_back(std::move(item));
}
};
int main() {
Manager manager;
auto item = std::make_unique<Item>(); // C++14
//auto item = std::unique_ptr<Item>(new Item); // C++11
manager.addItem(std::move(item));
}
This way, the items will be deleted when the Manager is destroyed without you having to write a destructor.
I suggest using std::vector instead of an array because it simplifies the management of the item archive.
It is impossible to tell what exactly is giving you the runtime error as you have not posted real code but using std::vector and std::unique_ptr instead will most likely fix it.
Live demo
There's no reason that Manager is not allowed to delete the Items. Your error could be that you're exceeding the ItemArchive array or deleting objects twice? It's hard to tell since you've re-written the code for the question.
I'd say try and use a system that you can debug and then you'll learn a lot quicker! Debuggers are just amazing things.

Why do they say that in the Proto-type Pattern - be used to simply duplicate the original object whenever a new one is needed?

I am trying to learn the design pattern. I am a C++ programmer. Currently, I am juggling with the Proto-type pattern. I could co-relate Prototype with the factory type. However, there are a lot of differences between factory and prototype pattern. For example, in the prototype pattern each derived class registers its prototype with the base/super class.
However, looking at the wikipedia article - I couldn't understood the following points.
Rather than retrieving the data and re-parsing it each time a new object is created, the prototype pattern can be used to simply duplicate the original object whenever a new one is needed.
avoid the inherent cost of creating a new object in the standard way (e.g., using the 'new' keyword) when it is prohibitively expensive for a given application.
Here is the program, I created to demonstrate the prototype pattern in C++. However, I cannot find any benefit out of it. How come a prototype pattern will help in quickly creating the object here. I can see that the object has to call 'new' every time. Here is the entire program, please correct me if you think that I haven't implemented the prototype pattern correctly.
Sorry for the long program - but trust me it is quite simple.
Like a factory object - here is the prototype class
-- basically an abstract.
class Itransport
{
public:
enum transportPacketType
{
udp,
tcp,
MAX
};
private:
static std::list<Itransport *> prototypesList;
protected:
virtual Itransport::transportPacketType getPacketType() = 0;
virtual Itransport* clone() = 0;
/** This will be called by the derived classes **/
static void registertoPrototypeList(Itransport *packet)
{
prototypesList.push_back(packet);
}
public:
virtual void showMessage() = 0;
static Itransport* makeClone(Itransport::transportPacketType packType)
{
std::list<Itransport *>::iterator it;
for(it = prototypesList.begin(); it != prototypesList.end(); it++)
{
if( (*it)->getPacketType() == packType )
{
return (*it)->clone();
}
}
}
virtual ~Itransport() = 0;
};
Itransport::~Itransport()
{
std::cout<<"Itransport Destructor called"<<std::endl;
}
std::list<Itransport *> Itransport::prototypesList;
Here is the concrete type of the Itransport Packet -
class udpPacket: public Itransport
{
private:
static udpPacket udpTransportPacket;
protected:
Itransport::transportPacketType getPacketType()
{
return Itransport::udp;
}
Itransport* clone()
{
return new udpPacket();
}
public:
void showMessage()
{
std::cout<<"This is a UDP Packet"<<std::endl;
}
udpPacket()
{
std::cout<<"UDP Packet Constructed"<<std::endl;
registertoPrototypeList(this);
}
~udpPacket()
{
std::cout<<"Destructor of udp called"<<std::endl;
}
};
static udpPacket udpTransportPacket;
Here is the client -
int main()
{
Itransport *udpPacket;
Itransport *udpPacket2;
udpPacket = Itransport::makeClone(Itransport::udp);
udpPacket->showMessage();
udpPacket2 = Itransport::makeClone(Itransport::udp);
udpPacket2->showMessage();
delete udpPacket;
delete udpPacket2;
return 0;
}
I couldn't find any benefits related to 'new' here. Please throw some light on it.
I can have a go at explaining the first point:
Rather than retrieving the data and re-parsing it each time a new
object is created, the prototype pattern can be used to simply
duplicate the original object whenever a new one is needed.
Imagine a computer game that has to create a lot of monsters. Say all the different types of monster are not known at compile time but you construct a monster of a particular type from some input data that provides information about what color the monster is, etc:
class Monster {
public:
Monster(InputDataHandle handle) {
// Retrieve input data...
// Parse input data...
}
void setPosition(Position);
};
Then every time you want to construct, say a red monster you have to retrieve the data and re-parse:
// Spawn a lot of red monsters
for (int i = 0; i != large_number; ++i) {
auto red = new Monster(red_monster_data); // Must retrieve data and re-parse!
red->setPosition(getRandomPosition());
game.add(red);
}
Clearly that is inefficient. One way of solving it is using the Prototype Pattern. You create one "prototype" red monster and every time you want to create an instance of a red monster you simply copy the prototype and you don't have to retrieve and re-parse the input data:
auto prototype_red_monster = new Monster(red_monster_data);
for (int i = 0; i != large_number; ++i) {
auto red = prototype_red_monster->clone();
red->setPosition(getRandomPosition());
game.add(red);
}
But how is the clone function implemented? This brings us to the second point which I don't really understand:
avoid the inherent cost of creating a new object in the standard way
(e.g., using the 'new' keyword) when it is prohibitively expensive for
a given application.
The clone function fundamentally has to allocate memory for the new object and copy data in from itself. I'm not sure I know what they are referring to when they talk about the "inherent cost of the new keyword". The examples are in Java and C# which have clone() and MemberwiseClone() respectively. In those languages you don't need to call new. I don't know how clone() and MemberwiseClone() are implemented but I don't see how they can "avoid the inherent cost of the new keyword".
In C++ we have to implement clone() ourselves and it will typically use new and use the copy constructor:
Monster* clone() {
return new Monster(*this);
}
In this case the copy constructor is much cheaper than creating the object from scratch. In your case it might not be.
The fact you cannot find any benefit from the Prototype Pattern in your case might mean it is the wrong pattern for your case and you will be better off with a different pattern like the Object Pool, Flyweight or Abstract Factory Pattern.

Porting an existing class structure to smart pointers

I know this question is rather long, but I was not sure how to explain my problem in a shorter way. The question itself is about class hierarchy design and, especially, how to port an existing hierarchy based on pointers to one using smart pointers. If anyone can come up with some way to simplify my explanation and, thus, make this question more generic, please let me know. In that way, it might be useful for more SO readers.
I am designing a C++ application for handling a system that allows me to read some sensors. The system is composed of remotes machines from where I collect the measurements. This application must actually work with two different subsystems:
Aggregated system: this type of system contains several components from where I collect measurements. All the communication goes through the aggregated system which will redirect the data to the specific component if needed (global commands sent to the aggregated system itself do not need to be transferred to individual components).
Standalone system: in this case there is just a single system and all the communication (including global commands) is sent to that system.
Next you can see the class diagram I came up with:
The standalone system inherits both from ConnMgr and MeasurementDevice. On the other hand, an aggregated system splits its functionality between AggrSystem and Component.
Basically, as a user what I want to have is a MeasurementDevice object and transparently send data to corresponding endpoint, be it an aggregated system or a standalone one.
CURRENT IMPLEMENTATION
This is my current implementation. First, the two base abstract classes:
class MeasurementDevice {
public:
virtual ~MeasurementDevice() {}
virtual void send_data(const std::vector<char>& data) = 0;
};
class ConnMgr {
public:
ConnMgr(const std::string& addr) : addr_(addr) {}
virtual ~ConnMgr() {}
virtual void connect() = 0;
virtual void disconnect() = 0;
protected:
std::string addr_;
};
These are the classes for an aggregated system:
class Component : public MeasurementDevice {
public:
Component(AggrSystem& as, int slot) : aggr_sys_(as), slot_(slot) {}
void send_data(const std::vector<char>& data) {
aggr_sys_.send_data(slot_, data);
}
private:
AggrSystem& aggr_sys_;
int slot_;
};
class AggrSystem : public ConnMgr {
public:
AggrSystem(const std::string& addr) : ConnMgr(addr) {}
~AggrSystem() { for (auto& entry : components_) delete entry.second; }
// overridden virtual functions omitted (not using smart pointers)
MeasurementDevice* get_measurement_device(int slot) {
if (!is_slot_used(slot)) throw std::runtime_error("Empty slot");
return components_.find(slot)->second;
}
private:
std::map<int, Component*> components_;
bool is_slot_used(int slot) const {
return components_.find(slot) != components_.end();
}
void add_component(int slot) {
if (is_slot_used(slot)) throw std::runtime_error("Slot already used");
components_.insert(std::make_pair(slot, new Component(*this, slot)));
}
};
This is the code for a standalone system:
class StandAloneSystem : public ConnMgr, public MeasurementDevice {
public:
StandAloneSystem(const std::string& addr) : ConnMgr(addr) {}
// overridden virtual functions omitted (not using smart pointers)
MeasurementDevice* get_measurement_device() {
return this;
}
};
These are factory-like functions responsible for creating ConnMgr and MeasurementDevice objects:
typedef std::map<std::string, boost::any> Config;
ConnMgr* create_conn_mgr(const Config& cfg) {
const std::string& type =
boost::any_cast<std::string>(cfg.find("type")->second);
const std::string& addr =
boost::any_cast<std::string>(cfg.find("addr")->second);
ConnMgr* ep;
if (type == "aggregated") ep = new AggrSystem(addr);
else if (type == "standalone") ep = new StandAloneSystem(addr);
else throw std::runtime_error("Unknown type");
return ep;
}
MeasurementDevice* get_measurement_device(ConnMgr* ep, const Config& cfg) {
const std::string& type =
boost::any_cast<std::string>(cfg.find("type")->second);
if (type == "aggregated") {
int slot = boost::any_cast<int>(cfg.find("slot")->second);
AggrSystem* aggr_sys = dynamic_cast<AggrSystem*>(ep);
return aggr_sys->get_measurement_device(slot);
}
else if (type == "standalone") return dynamic_cast<StandAloneSystem*>(ep);
else throw std::runtime_error("Unknown type");
}
And finally here it is main(), showing a very simple usage case:
#define USE_AGGR
int main() {
Config config = {
{ "addr", boost::any(std::string("192.168.1.10")) },
#ifdef USE_AGGR
{ "type", boost::any(std::string("aggregated")) },
{ "slot", boost::any(1) },
#else
{ "type", boost::any(std::string("standalone")) },
#endif
};
ConnMgr* ep = create_conn_mgr(config);
ep->connect();
MeasurementDevice* dev = get_measurement_device(ep, config);
std::vector<char> data; // in real life data should contain something
dev->send_data(data);
ep->disconnect();
delete ep;
return 0;
}
PROPOSED CHANGES
First of all, I wonder whether there is a way to avoid the dynamic_cast in get_measurement_device. Since AggrSystem::get_measurement_device(int slot) and StandAloneSystem::get_measurement_device() have different signatures, it is not possible to create a common virtual method in the base class. I was thinking to add a common method accepting a map containing the options (e.g., the slot). In that case, I would not need to do the dynamic casting. Is this second approach preferable in terms of a cleaner design?
In order to port the class hierarchy to smart pointers I used unique_ptr. First I changed the map of components in AggrSystem to:
std::map<int, std::unique_ptr<Component> > components_;
The addition of a new Component now looks like:
void AggrSystem::add_component(int slot) {
if (is_slot_used(slot)) throw std::runtime_error("Slot already used");
components_.insert(std::make_pair(slot,
std::unique_ptr<Component>(new Component(*this, slot))));
}
For returning a Component I decided to return a raw pointer since the lifetime of a Component object is defined by the lifetime of an AggrSystem object:
MeasurementDevice* AggrSystem::get_measurement_device(int slot) {
if (!is_slot_used(slot)) throw std::runtime_error("Empty slot");
return components_.find(slot)->second.get();
}
Is returning a raw pointer a correct decision? If I use a shared_ptr, however, then I run into problems with the implementation for the standalone system:
MeasurementDevice* StandAloneSystem::get_measurement_device() {
return this;
}
In this case I cannot return a shared_ptr using this. I guess I could create one extra level of indirection and have something like StandAloneConnMgr and StandAloneMeasurementDevice, where the first class would hold a shared_ptr to an instance of the second.
So, overall, I wanted to ask whether this a good approach when using smart pointers. Would it be preferable to use a map of shared_ptr and return a shared_ptr too, or is it better the current approach based on using unique_ptr for ownership and raw pointer for accessing?
P.S: create_conn_mgr and main are changed as well so that instead of using a raw pointer (ConnMgr*) now I use unique_ptr<ConnMgr>. I did not add the code since the question was already long enough.
First of all, I wonder whether there is a way to avoid the
dynamic_cast in get_measurement_device.
I would attempt to unify the get_measurement_device signatures so that you can make this a virtual function in the base class.
So, overall, I wanted to ask whether this a good approach when using
smart pointers.
I think you've done a good job. You've basically converted your "single ownership" news and deletes to unique_ptr in a fairly mechanical fashion. This is exactly the right first (and perhaps last) step.
I also think you made the right decision in returning raw pointers from get_measurement_device because in your original code the clients of this function did not take ownership of this pointer. Dealing with raw pointers when you do not intend to share or transfer ownership is a good pattern that most programmers will recognize.
In summary, you've correctly translated your existing design to use smart pointers without changing the semantics of your design.
From here if you want to study the possibility of changing your design to one involving shared ownership, that is a perfectly valid next step. My own preference is to prefer unique ownership designs until a use case or circumstance demands shared ownership.
Unique ownership is not only more efficient, it is also easier to reason about. That ease in reasoning typically leads to fewer accidental cyclic memory ownership patters (cyclic memory ownership == leaked memory). Coders who just slap down shared_ptr every time they see a pointer are far more likely to end up with memory ownership cycles.
That being said, cyclic memory ownership is also possible using only unique_ptr. And if it happens, you need weak_ptr to break the cycle, and weak_ptr only works with shared_ptr. So the introduction of an ownership cycle is another good reason to migrate to shared_ptr.

Factory method anti-if implementation

I'm applying the Factory design pattern in my C++ project, and below you can see how I am doing it. I try to improve my code by following the "anti-if" campaign, thus want to remove the if statements that I am having. Any idea how can I do it?
typedef std::map<std::string, Chip*> ChipList;
Chip* ChipFactory::createChip(const std::string& type) {
MCList::iterator existing = Chips.find(type);
if (existing != Chips.end()) {
return (existing->second);
}
if (type == "R500") {
return Chips[type] = new ChipR500();
}
if (type == "PIC32F42") {
return Chips[type] = new ChipPIC32F42();
}
if (type == "34HC22") {
return Chips[type] = new Chip34HC22();
}
return 0;
}
I would imagine creating a map, with string as the key, and the constructor (or something to create the object). After that, I can just get the constructor from the map using the type (type are strings) and create my object without any if. (I know I'm being a bit paranoid, but I want to know if it can be done or not.)
You are right, you should use a map from key to creation-function.
In your case it would be
typedef Chip* tCreationFunc();
std::map<std::string, tCreationFunc*> microcontrollers;
for each new chip-drived class ChipXXX add a static function:
static Chip* CreateInstance()
{
return new ChipXXX();
}
and also register this function into the map.
Your factory function should be somethink like this:
Chip* ChipFactory::createChip(std::string& type)
{
ChipList::iterator existing = microcontrollers.find(type);
if (existing != microcontrollers.end())
return existing->second();
return NULL;
}
Note that copy constructor is not needed, as in your example.
The point of the factory is not to get rid of the ifs, but to put them in a separate place of your real business logic code and not to pollute it. It is just a separation of concerns.
If you're desperate, you could write a jump table/clone() combo that would do this job with no if statements.
class Factory {
struct ChipFunctorBase {
virtual Chip* Create();
};
template<typename T> struct CreateChipFunctor : ChipFunctorBase {
Chip* Create() { return new T; }
};
std::unordered_map<std::string, std::unique_ptr<ChipFunctorBase>> jumptable;
Factory() {
jumptable["R500"] = new CreateChipFunctor<ChipR500>();
jumptable["PIC32F42"] = new CreateChipFunctor<ChipPIC32F42>();
jumptable["34HC22"] = new CreateChipFunctor<Chip34HC22>();
}
Chip* CreateNewChip(const std::string& type) {
if(jumptable[type].get())
return jumptable[type]->Create();
else
return null;
}
};
However, this kind of approach only becomes valuable when you have large numbers of different Chip types. For just a few, it's more useful just to write a couple of ifs.
Quick note: I've used std::unordered_map and std::unique_ptr, which may not be part of your STL, depending on how new your compiler is. Replace with std::map/boost::unordered_map, and std::/boost::shared_ptr.
No you cannot get rid of the ifs. the createChip method creats a new instance depending on constant (type name )you pass as argument.
but you may optimaze yuor code a little removing those 2 line out of if statment.
microcontrollers[type] = newController;
return microcontrollers[type];
To answer your question: Yes, you should make a factory with a map to functions that construct the objects you want. The objects constructed should supply and register that function with the factory themselves.
There is some reading on the subject in several other SO questions as well, so I'll let you read that instead of explaining it all here.
Generic factory in C++
Is there a way to instantiate objects from a string holding their class name?
You can have ifs in a factory - just don't have them littered throughout your code.
struct Chip{
};
struct ChipR500 : Chip{};
struct PIC32F42 : Chip{};
struct ChipCreator{
virtual Chip *make() = 0;
};
struct ChipR500Creator : ChipCreator{
Chip *make(){return new ChipR500();}
};
struct PIC32F42Creator : ChipCreator{
Chip *make(){return new PIC32F42();}
};
int main(){
ChipR500Creator m; // client code knows only the factory method interface, not the actuall concrete products
Chip *p = m.make();
}
What you are asking for, essentially, is called Virtual Construction, ie the ability the build an object whose type is only known at runtime.
Of course C++ doesn't allow constructors to be virtual, so this requires a bit of trickery. The common OO-approach is to use the Prototype pattern:
class Chip
{
public:
virtual Chip* clone() const = 0;
};
class ChipA: public Chip
{
public:
virtual ChipA* clone() const { return new ChipA(*this); }
};
And then instantiate a map of these prototypes and use it to build your objects (std::map<std::string,Chip*>). Typically, the map is instantiated as a singleton.
The other approach, as has been illustrated so far, is similar and consists in registering directly methods rather than an object. It might or might not be your personal preference, but it's generally slightly faster (not much, you just avoid a virtual dispatch) and the memory is easier to handle (you don't have to do delete on pointers to functions).
What you should pay attention however is the memory management aspect. You don't want to go leaking so make sure to use RAII idioms.