Creating a system wide resource C++ - c++

I am having an issue designing a software. I have a very big object(BO), let's say a map of dynamic arrays, that I need to access across various classes. Each time a class uses BO, it adds new data to it, or uses some of the data in BO to do computation.
As a newbie, I am lost on how to design such an object in C++ so that my code design and architecture is good. Making a global variable is not efficient enough, researched on Singleton but found out the rule is you can only access the object, not change it.
Anyone can point me in the right direction? what design pattern should I follow that is the most efficient and scalable?
Thanks
Based on the answers here, is the following a correct design- it's psudo!
Class BigObject {
private static BigObject instance = null;
private map;
private BigObject() { }
public static BigObject getInstance() {
if (instance == null) {
instance = new BigObject();
}
return instance;
}
public getArray(string key) {
return map[key];
}
public setBigObject(string key, Array value) {
map.insert(key, value);
}

"but found out the rule is you can only access the object, not change it."
You probably misunderstood something there?
The only purpose of a singleton is to guarantee to have a single instance of a class. You can still change its state as is permitted by its class member functions.
Regarding the singleton implementation you have posted in your updated question you should improve it to be thread safe (following Scott Meyer's Singleton):
class BigObject {
std::map<std::string,Array> map;
BigObject() { }
public:
static BigObject& getInstance() {
static BigObject instance;
return instance;
}
const Array& getArray(std::string key) const {
return map[key];
}
void setBigObject(string key, Array value) {
map.insert(key, value);
}
};
But as Singleton tightly couples your client code to the singleton class, you probably should declare an interface for your BigObject, take references in the classes that need to have access, and pass an instance from construction:
struct IBigObject {
virtual void doCostlyCalculations() = 0;
virtual void updateData(std::vector<int> record) = 0;
virtual ~IBigObject() {}
};
class BigObject : public IBigObject {
virtual void doCostlyCalculations() {
// Implementation ...
}
virtual void updateData(std::vector<int> record) {
// Implementation ...
}
};
class ClientA {
IBigObject& bo_;
public:
ClientA(IBigObject& bo) : bo_(bo) {}
}
class ClientB {
IBigObject& bo_;
public:
ClientA(IBigObject& bo) : bo_(bo) {}
}
int main() {
BigObject bo;
ClientA ca(bo);
ClientB cb(bo);
// ...
};

Related

How to properly store inherited objects in std::map for good accessibility?

This is my first C++ related programming question. I consider myself a beginner in programming even though I have dealt with C++ in some ways for about half a year. My question yields at an inheritance problem that I recently faced in my work.
I have a class NodeMaster that should handle a container (right now a map) of different child objects inherited from the same base class NBase - accessing them, change data, ...
// Base class
class NBase
{
private:
int m_ID;
public:
NBase() { m_ID = 0; };
~NBase() {};
...
}
// Child class
class NSampler : NBase
{
private:
int m_ID;
std::string m_state;
public:
NSampler(std::string state) : {
m_ID = 1;
m_state = state;
}
...
}
The childs of NBase are 'registered' into the map via some arbitrary index:
#include "NBase.h"
class NodeMaster
{
private:
std::map<int, std::shared_ptr<sbr::NBase>> m_mpNodes;
public:
void register_node(int nIdx, std::shared_ptr<sbr::NBase> pNode)
{
this->m_mpNodes.insert(std::pair<int, std::shared_ptr<sbr::NBase>>(nIdx, pNode->clone()));
}
std::shared_ptr<sbr::NBase> get_node(int idx)
{
std::map<int, std::shared_ptr<sbr::NBase>>::iterator itr;
for (itr = this->m_mpNodes.begin(); itr != this->m_mpNodes.end(); ++itr) {
if (itr->first == idx) {
return itr->second;
}
}
}
I read about this problem on SO to imporve my solution step-by-step and also read about the issue of Object Slicing. Therefore I put the objects into a std::shared_ptr to guarantee the 'polymorphic behaviour' throughout the process. So far everything is good and I can add the Child class objects to the container via
std::shared_ptr<sbr::NSampler> sampler(std::make_shared<sbr::NSampler>("SAMPLER_INIT"));
NodeMaster nodeMater;
nodeMaster.register_node(sampler->get_ID(), sampler);
Now what gives me headaches is how to properly access the elements of m_mpNodes later in the code ... The nodeMaster itself is passed to another function by reference pre_process_lin(nodeMaster, m_Links) and to access the elements inside this function I expected to just write e.g. nodeMaster.get_node(1) but that does not return the inherited object 'NSampler' but rather 'NBase' ... to retrieve 'NSampler' I had to use a dynamic_cast for smart pointers:
nodeMaster.get_node(1); // NBase
...
std::shared_ptr<sbr::NSampler> test_sampler = std::dynamic_pointer_cast<sbr::NSampler>(nodeMaster.get_node(1)); // NSampler
To get this going I had to add a copy ctor to both the NBase and the NSampler (for using the covariance feature of C++) and considering that I deal with smart pointers I read this blog post to implement the copy ctor into the classes
// Base class
class NBase
{
private:
int m_ID;
public:
NBase() { m_ID = 0; };
~NBase() {};
public:
std::shared_ptr<NBase> clone() const
{
return std::shared_ptr<NBase>(this->clone_impl());
}
private:
virtual NBase* clone_impl() const = 0;
...
}
// Child class
class NSampler : NBase
{
private:
int m_ID;
std::string m_state;
public:
NSampler(std::string state) : {
m_ID = 1;
m_state = state;
}
public:
std::shared_ptr<NSampler> clone() const
{
return std::shared_ptr<NSampler>(this->clone_impl());
}
private:
virtual NSampler* clone_impl() const override
{
return new NSampler(*this);
}
...
}
With this setup I solve my problem of stacking together a bunch of inherited class objects into some container (map), but since this specific copy-ctor is called (in order to be able to add them to the container) the initial member variables (e.g. m_state) get overwritten after 're-calling' the objects from the map.
Is there a better way to wrap the process of inheritance, packing to container and unpacking without losing object data on the run due to the copy-ctor above?

How can i accsess different parts of my inherited code

Hi i have a question regarding how to access parts of inherited code.
Say i have this WorldObject that is a base class for alot of other objects. Then i have a class Chest that inherit from WorldObject and also from the abstract class OpenAble, with some methods like open and unlock.
In my main i have a vector of WorldObjects that i iterate through with a for loop. Now to the question, how can i check if a worldobject is also of OpenAble and how can i access the methods in OpenAble.
class WorldObject
{
... //implementation
};
class OpenAble
{
public:
OpenAble(){}
virtual ~OpenAble(){}
virtual void Open() = 0;
virtual void Unlock(int k) = 0;
};
class Chest : public WorldObject, public OpenAble
{
... //implementation
};
main()
{
std::vector<WorldObject> objVector; //vector with several Worldobjects
for (int i =0; i < objVector.Size(); i++)
{
//check if a WorldObject is also of openable
//Do som actions like, open or unlock
//How?
}
};
You could do a dynamic_cast<OpenAble>. This will throw an error if it is the wrong type though which is relatively expensive given that it is quite likely that the object will be the wrong type.
try{
OpenAble& opener = dynamic_cast<OpenAble&>(worldObj);
} catch (std::bad_cast& ex){
//not openable
}
BTW: As pointed out in the comments below, if you use a pointer to the base class in your container instead of references, then you can (and should) use the pointer version of dynamic_cast which will return a null in the case that your object is not OpenAble. Checking that in your case would be a lot more efficient than throwing and catching exceptions.
I would recommend an entirely different approach though. Inject your base class with an "OpenPolicy".
E.g.
class CanOpenPolicy {
public:
boolean canOpen(){ return true; };
boolean canClose(){ return true; };
boolean isOpen(){ return openState; };
void open(){ openState = OPEN; };
void close(){ openState = CLOSED; };
}
class NoOpenPolicy {
public:
boolean canOpen(){ return false; };
boolean canClose(){ return false; };
boolean isOpen(){ return CLOSED; };
void open(){ throw IllegalWorldObjectAction("OpenPolicy disallows operation"); };
void close(){ throw IllegalWorldObjectAction("OpenPolicy disallows operation"); };
}
//injection via template (no need for base "OpenPolicy" class, maybe some
// obscure error codes at compile though)
// Implicit interface based on how you use the injected policy.
template<OpenPol>
class WorldObject {
private:
// CTOR part of the injected contract so you are not tied to knowing how to
// build the policy. This is a key benefit over interface based injection.
OpenPol openPol;
...
public:
...
void open(){
if(openPol.canOpen()){
openPol.open();
}
}
...
}
That's not tested or anything. Just to illustrate the idea. You can add multiple policies for different possible operations and the best thing is that you won't need a lot of hierarchies.
To use it just do something like this:
std::unique_ptr<WorldObject>( new Chest() );
std::unique_ptr<WorldObject>( new Banana() );
std::unique_ptr<WorldObject>( new Chair() );
where:
class Chest : public WorldObject<CanOpenPolicy> {
// Very little implementation in here.
// Most of it is handled in the base class and the injected policies :)
}
class Banana: public WorldObject<CanOpenPolicy> {
}
class Chair : public WorldObject<NoOpenPolicy> {
}
The most important thing, even though you may not like this, is to not throw away type information in the first place.
Collections of generic "object" is a Java'ism, it's not how to do things in C++.
That said, provided the statically known class is polymorphic (has at least one virtual member function), you can use dynamic_cast or typeid. This functionality is known as RTTI, short for Run Time Type Information. With some compilers you have to use special options to enable RTTI.
Idiomatic use of dynamic_cast:
WorldObject* p = ...;
if( auto p_openable = dynamic_cast<OpenAble*>( p ) )
{
// use p_openable
}
Note that dynamic_cast to pointer signals failure by returning a nullpointer, while dynamic_cast to reference signals failure by throwing an exception, since there are no nullreferences.
The simple (obvious) solution is to use dynamic_cast and cast your objects to OpenAble.
The problem with "the simple (obvious) solution" is that usually, use of dynamic_cast shows a lack of flexibility in your class hierarchy and is a symptom of a design problem.
I would offer the OpenAble interface as a set of behavior exposed through a handle:
class OpenAble { /* ... */ };
class WorldObject
{
//implementation
virtual OpenAble* GetOpener() { return nullptr; }
};
class Chest: public WorldObject {
struct ChestOpener: public OpenAble {
Chest *c;
virtual void Open() {
// do stuff with c
}
};
std::unique_ptr<OpenAble> chest_opener;
public:
virtual OpenAble* GetOpener() {
if(!chest_opener) {
chest_opener = new ChestOpener{ this };
}
return chest_opener.get();
}
};
Client code:
std::vector<WorldObject> objVector; //vector with several Worldobjects
for(auto &obj: objVector)
{
if(auto openerHandle = obj.GetOpener())
openerHandle->Open();
}

How to return same instance for every class initialization in C++?

I want to create a class that can only have one instance. If I try to make another instance of the class, it will return the first instance.
I think you are searching Singleton pattern in C++. Here is implementation and here linux tutorial for singleton pattern in C++
I think what you want is closer to MonoState, than Singleton.
MonoState works by having all objects share the same state through static member variables. Whilst the instances are different, the data returned by those is the same. Here is a simple implementation:
class MonoStateSession {
private:
static int _SessionId;
public:
void SetSessionId(int newSessionId) {
//Put threading checks/locks here
_SessionId = newSessionId;
}
int GetSessionId() {
return _SessionId;
}
}
//Usage
MonoStateSession session1 = new MonoStateSession();
session1.SetSessionId(123);
MonoStateSession session2 = new MonoStateSession();
assert(session2.GetSessionId() == 123);
No... but you can get close to that. For example you can create a class where every instance is just a clone of the same real object... for example:
struct TheRealObject
{
std::string s;
TheRealObject() { ... }
void foo(int x) { ... }
double bar(char y) { ... }
static TheRealObject& getInstance()
{
static TheRealObject trb;
return trb;
}
};
struct MyObject
{
std::string& s;
MyObject() : s(TheRealObject::getInstance().s) {}
void foo(int x) { TheRealObject::getInstance().foo(x); }
double bar(char y) { return TheRealObject::getInstance().bar(y); }
};
Note that every MyObject instance will still be a distinct object (with its own address for example) but they will just act as a trampoline to the only instance existing of TheRealObject both for method and data member access.
Why do you want to do something this strange? May be you're just looking for a singleton instead (like the TheRealObject in the above)?

Resolving a Forward Declaration Issue Involving a State Machine in C++

I've recently returned to C++ development after a hiatus, and have a question regarding
implementation of the State Design Pattern. I'm using the vanilla pattern, exactly as
per the GoF book.
My problem is that the state machine itself is based on some hardware used as part of
an embedded system - so the design is fixed and can't be changed. This results in a
circular dependency between two of the states (in particular), and I'm trying to
resolve this. Here's the simplified code (note that I tried to resolve this by using
headers as usual but still had problems - I've omitted them in this code snippet):
#include <iostream>
#include <memory>
using namespace std;
class Context
{
public:
friend class State;
Context() { }
private:
State* m_state;
};
class State
{
public:
State() { }
virtual void Trigger1() = 0;
virtual void Trigger2() = 0;
};
class LLT : public State
{
public:
LLT() { }
void Trigger1() { new DH(); }
void Trigger2() { new DL(); }
};
class ALL : public State
{
public:
ALL() { }
void Trigger1() { new LLT(); }
void Trigger2() { new DH(); }
};
// DL needs to 'know' about DH.
class DL : public State
{
public:
DL() { }
void Trigger1() { new ALL(); }
void Trigger2() { new DH(); }
};
class HLT : public State
{
public:
HLT() { }
void Trigger1() { new DH(); }
void Trigger2() { new DL(); }
};
class AHL : public State
{
public:
AHL() { }
void Trigger1() { new DH(); }
void Trigger2() { new HLT(); }
};
// DH needs to 'know' about DL.
class DH : public State
{
public:
DH () { }
void Trigger1() { new AHL(); }
void Trigger2() { new DL(); }
};
int main()
{
auto_ptr<LLT> llt (new LLT);
auto_ptr<ALL> all (new ALL);
auto_ptr<DL> dl (new DL);
auto_ptr<HLT> hlt (new HLT);
auto_ptr<AHL> ahl (new AHL);
auto_ptr<DH> dh (new DH);
return 0;
}
The problem is basically that in the State Pattern, state transitions are made by
invoking the the ChangeState method in the Context class, which invokes the
constructor of the next state.
Because of the circular dependency, I can't invoke the constructor because it's
not possible to pre-define both of the constructors of the 'problem' states.
I had a look at this article, and the template method which seemed to be the ideal solution - but it doesn't compile and my knowledge of templates is a rather limited...
The other idea I had is to try and introduce a Helper class to the subclassed states,
via multiple inheritance, to see if it's possible to specify the base class's constructor
and have a reference to the state subclasse's constructor. But I think that was rather
ambitious...
Finally, would a direct implmentation of the Factory Method Design Pattern be the best way
to resolve the entire problem?
You can define the member functions outside of the class definitions, e.g.,
class DL : public State
{
public:
void Trigger2();
};
inline void DL::Trigger2() { new DH(); }
Define the member functions that rely on later class definitions after those classes are defined. The inline keyword is only necessary if you define the member function outside of the class in the header file.
As an aside, why are you just using new DH() in your functions; you're leaking memory everywhere!

Looking for a better C++ class factory

I have an application that has several objects (about 50 so far, but growing). There is only one instance of each of these objects in the app and these instances get shared among components.
What I've done is derive all of the objects from a base BrokeredObject class:
class BrokeredObject
{
virtual int GetInterfaceId() = 0;
};
And each object type returns a unique ID. These IDs are maintained in a header file.
I then have an ObjectBroker "factory". When someone needs an object, then call GetObjectByID(). The boker looks in an STL list to see if the object already exists, if it does, it returns it. If not, it creates it, puts it in the list and returns it. All well and good.
BrokeredObject *GetObjectByID(int id)
{
BrokeredObject *pObject;
ObjectMap::iterator = m_objectList.find(id);
// etc.
if(found) return pObject;
// not found, so create
switch(id)
{
case 0: pObject = new TypeA; break;
case 1: pObject = new TypeB; break;
// etc.
// I loathe this list
}
// add it to the list
return pObject;
}
What I find painful is maintaining this list of IDs and having to have each class implement it. I have at least made my consumer's lives slightly easier by having each type hold info about it's own ID like this:
class TypeA : public BrokeredObject
{
static int get_InterfaceID() { return IID_TYPEA; }
int GetInterfaceID() { return get_InterfaceID(); }
};
So I can get an object like this:
GetObjectByID(TypeA::get_InterfaceID());
Intead of having to actually know what the ID mapping is but I still am not thrilled with the maintenance and the potential for errors. It seems that if I know the type, why should I also have to know the ID?
What I long for is something like this in C#:
BrokeredObject GetOrCreateObject<T>() where T : BrokeredObject
{
return new T();
}
Where the ObjectBroker would create the object based on the type passed in.
Has C# spoiled me and it's just a fact of life that C++ can't do this or is there a way to achieve this that I'm not seeing?
Yes, there is a way. A pretty simple even in C++ to what that C# code does (without checking for inheritance though):
template<typename T>
BrokeredObject * GetOrCreateObject() {
return new T();
}
This will work and do the same as the C# code. It is also type-safe: If the type you pass is not inherited from BrokeredObject (or isn't that type itself), then the compiler moans at the return statement. It will however always return a new object.
Singleton
As another guy suggested (credits to him), this all looks very much like a fine case for the singleton pattern. Just do TypeA::getInstance() to get the one and single instance stored in a static variable of that class. I suppose that would be far easier than the above way, without the need for IDs to solve it (i previously showed a way using templates to store IDs in this answer, but i found it effectively is just what a singleton is).
I've read that you will leave the chance open to have multiple instances of the classes. One way to do that is to have a Mingleton (i made up that word :))
enum MingletonKind {
SINGLETON,
MULTITON
};
// Singleton
template<typename D, MingletonKind>
struct Mingleton {
static boost::shared_ptr<D> getOrCreate() {
static D d;
return boost::shared_ptr<D>(&d, NoopDel());
}
struct NoopDel {
void operator()(D const*) const { /* do nothing */ }
};
};
// Multiton
template<typename D>
struct Mingleton<D, MULTITON> {
static boost::shared_ptr<D> getOrCreate() {
return boost::shared_ptr<D>(new D);
}
};
class ImASingle : public Mingleton<ImASingle, SINGLETON> {
public:
void testCall() { }
// Indeed, we have to have a private constructor to prevent
// others to create instances of us.
private:
ImASingle() { /* ... */ }
friend class Mingleton<ImASingle, SINGLETON>;
};
class ImAMulti : public Mingleton<ImAMulti, MULTITON> {
public:
void testCall() { }
// ...
};
int main() {
// both do what we expect.
ImAMulti::getOrCreate()->testCall();
ImASingle::getOrCreate()->testCall();
}
Now, you just use SomeClass::getOrCreate() and it cares about the details. The custom deleter in the singleton case for shared_ptr makes deletion a no-op, because the object owned by the shared_ptr is allocated statically. However, be aware of problems of destruction order of static variables: Static initialization order fiasco
The way I would solve this problem is using what I would call the Static Registry Pattern, which in my mine mind is the C++ version of dependency injection.
Basically you have a static list of builder objects of a type that you use to build objects of another type.
A basic static registry implementation would look like:
template <class T>
class StaticRegistry
{
public:
typedef std::list<T*> Container;
static StaticRegistry<T>& GetInstance()
{
if (Instance == 0)
{
Instance = new StaticRegistry<T>;
}
return *Instance;
}
void Register(T* item)
{
Items.push_back(item);
}
void Deregister(T* item)
{
Items.remove(item);
if (Items.empty())
{
delete this;
Instance = 0;
}
}
typedef typename Container::const_iterator const_iterator;
const_iterator begin() const
{
return Items.begin();
}
const_iterator end() const
{
return Items.end();
}
protected:
StaticRegistry() {}
~StaticRegistry() {}
private:
Container Items;
static StaticRegistry<T>* Instance;
};
template <class T>
StaticRegistry<T>* StaticRegistry<T>::Instance = 0;
An implementation of BrokeredObjectBuilder could look like this:
class BrokeredObjectBuilderBase {
public:
BrokeredObjectBuilderBase() { StaticRegistry<BrokeredObjectBuilderBase>::GetInstance().Register(this); }
virtual ~BrokeredObjectBuilderBase() { StaticRegistry<BrokeredObjectBuilderBase>::GetInstance().Deregister(this); }
virtual int GetInterfaceId() = 0;
virtual BrokeredObject* MakeBrokeredObject() = 0;
};
template<class T>
class BrokeredObjectBuilder : public BrokeredObjectBuilderBase {
public:
BrokeredObjectBuilder(unsigned long interface_id) : m_InterfaceId(interface_id) { }
virtual int GetInterfaceId() { return m_InterfaceId; }
virtual T* MakeBrokeredObject() { return new T; }
private:
unsigned long m_InterfaceId;
};
class TypeA : public BrokeredObject
{
...
};
// Create a global variable for the builder of TypeA so that it's
// included in the BrokeredObjectBuilderRegistry
BrokeredObjectBuilder<TypeA> TypeABuilder(TypeAUserInterfaceId);
typedef StaticRegistry<BrokeredObjectBuilderBase> BrokeredObjectBuilderRegistry;
BrokeredObject *GetObjectByID(int id)
{
BrokeredObject *pObject(0);
ObjectMap::iterator = m_objectList.find(id);
// etc.
if(found) return pObject;
// not found, so create
BrokeredObjectBuilderRegistry& registry(BrokeredObjectBuilderRegistry::GetInstance());
for(BrokeredObjectBuilderRegistry::const_iterator it = registry.begin(), e = registry.end(); it != e; ++it)
{
if(it->GetInterfaceId() == id)
{
pObject = it->MakeBrokeredObject();
break;
}
}
if(0 == pObject)
{
// userinterface id not found, handle this here
...
}
// add it to the list
return pObject;
}
Pros:
All the code that knows about creating the types is seperated out into the builders and the BrokeredObject classes don't need to know about it.
This implementation can be used in libraries and you can control on a per project level what builders are pulled into a project using a number of different techniques.
The builders can be as complex or as simple (like above) as you want them to be.
Cons:
There is a wee bit of infrastructure involved (but not too much).
The flexability of defining the global variables to include what builders to include in your project does make it a little messy to work with.
I find that people find it hard to understand this pattern, I'm not sure why.
It's sometimes not easy to know what is in the static registry at any one time.
The above implementation leaks one bit of memory. (I can live with that...)
The above implementation is very simple, you can extend it in lots of different ways depending on the requirements you have.
Use a template class as the broker.
Make the instance a static member of the function. It will be created on first use and automagically-destroyed when the program exits.
template <class Type>
class BrokeredObject
{
public:
static Type& getInstance()
{
static Type theInstance;
return theInstance;
}
};
class TestObject
{
public:
TestObject()
{}
};
int main()
{
TestObject& obj =BrokeredObject<TestObject>::getInstance();
}
Instead of GetInterfaceId() in the BrokeredObject base class, you could define that pure virtual method:
virtual BrokeredObject& GetInstance()=0;
And in the derived classes you'll return from that method the instance of the particular derived class, if it's already created, if not, you'll first create it and then return it.
It doesn't look like you need the global object to do the management, so why not move everything into the classes themselves?
template <class Type>
class BrokeredObject
{
protected:
static Type *theInstance;
public:
static Type *getOrCreate()
{
if (!theInstance) {
theInstance = new Type();
}
return theInstance;
}
static void free()
{
delete theInstance;
}
};
class TestObject : public BrokeredObject<TestObject>
{
public:
TestObject()
{}
};
int
main()
{
TestObject *obj = TestObject::getOrCreate();
}
If you have RTTI enabled, you can get the class name using typeid.
One question, why are you using a factory rather than using a singleton pattern for each class?
Edit: OK, so you don't want to be locked into a singleton; no problem. The wonderful thing about C++ is it gives you so much flexibility. You could have a GetSharedInstance() member function that returns a static instance of the class, but leave the constructor public so that you can still create other instances.
If you always know the type at compile time there is little point in calling BrokeredObject* p = GetObjectByID(TypeA::get_InterfaceID()) instead of TypeA* p = new TypeA or TypeA o directly.
If you on the other hand don't know the exact type at compile time, you could use some kind of type registry.
template <class T>
BrokeredObject* CreateObject()
{
return new T();
}
typedef int type_identity;
typedef std::map<type_identity, BrokeredObject* (*)()> registry;
registry r;
class TypeA : public BrokeredObject
{
public:
static const type_identity identity;
};
class TypeB : public BrokeredObject
{
public:
static const type_identity identity;
};
r[TypeA::identity] = &CreateObject<TypeA>;
r[TypeB::identity] = &CreateObject<TypeB>;
or if you have RTTI enabled you could use type_info as type_identity:
typedef const type_info* type_identity;
typedef std::map<type_identity, BrokeredObject* (*)()> registry;
registry r;
r[&typeid(TypeA)] = &CreateObject<TypeA>;
r[&typeid(TypeB)] = &CreateObject<TypeB>;
Each new class could of course, in any case, be self-registering in the registry, making the registration decentralized instead of centralized.
You should almost certainly be using dependency injection.
Why not this?
template
BrokeredObject* GetOrCreateObject()
{
return new T();
}
My use-case tended to get a little more complex - I needed the ability to do a little bit of object initialization and I needed to be able to load objects from different DLLs based on configuration (e.g. simulated versus actual for hardware). It started looking like COM and ATL was where I was headed, but I didn't want to add the weight of COM to the OS (this is being done in CE).
What I ended up going with was template-based (thanks litb for putting me on track) and looks like this:
class INewTransModule
{
public:
virtual bool Init() { return true; }
virtual bool Shutdown() { return true; }
};
template <typename T>
struct BrokeredObject
{
public:
inline static T* GetInstance()
{
static T t;
return &t;
}
};
template <>
struct BrokeredObject<INewTransModule>
{
public:
inline static INewTransModule* GetInstance()
{
static INewTransModule t;
// do stuff after creation
ASSERT(t.Init());
return &t;
}
};
class OBJECTBROKER_API ObjectBroker
{
public:
// these calls do configuration-based creations
static ITraceTool *GetTraceTool();
static IEeprom *GetEeprom();
// etc
};
Then to ensure that the objects (since they're templated) actually get compiled I added definitions like these:
class EepromImpl: public BrokeredObject<EepromImpl>, public CEeprom
{
};
class SimEepromImpl: public BrokeredObject<SimEepromImpl>, public CSimEeprom
{
};