In my program I have a class (M) that is needed by very basic parts of a system - I only need one instance of M.
Other systems may need to have access to M and these other systems are within other systems.
For illustration:
1 2 3 4 5 6 7 8 9 10 11 12
Class A3a requires access to M.
M (class that class A3a requires)
A (class)
A1 (class within A)
A2
A3
A3a (class within A3)
..
..
..
My solution to this issue was to create a singleton and now I have a lot of singletons (such as one for sound, graphics, networking, etc). Is this proper? It feels strange that I'm using these singletons all over the place.
Another problem was that classes that needed a singleton accessed it often enough to justify creating a static pointer within that class to that singleton. The issue here is that the only proper way to initialize it was to use a static function to do so. Leading to a large number of classes having static initializing functions.
A way I used to get around that was to create a class with a static pointer to a singleton, which is only initialized once. And then inherit from that class - which now means that class has access to that static init. However, this leads to multiple inheritance, which I've heard is not a good thing to have. What are your suggestions?
Illustration:
1 2 3 4 5 6 7 8 9 10 11 12 13
class B{
public:
staticvoid Init( M ){ Maccessor = M; }
private:
static M *Maccessor;
};
class A3a{
public:
staticvoid Init( M ){ Maccessor = M; }
private:
static M *Maccessor;
};
To
1 2 3 4 5 6 7 8
class MBase{
public: staticvoid Init( M ){ Maccessor = M; }
protected: static M *MAccessor;
};
class B : public MBase{...};
class A3a : public MBase{...};
The inheritance method is not the way to go, but not necessarily because of multiple inheritance -- it's just not
intuitive to me. (Multiple inheritance does have its good uses, but that is a topic for another thread).
I think you are saying that the justification for making static pointers in your classes is so that you can shorten
the lines of code that require the pointer? ie,
Sound::GetInstance()->Play( "bing.wav" );
vs.
pSound->Play( "bing.wav" );
?
If so, why not have a helper function in the sound module?
K I think I'll try that, would it be weird to make it a template?
1 2 3 4 5 6 7 8 9 10 11 12 13 14
template <class A>
class InstanceTemplate
{
public:
static A &GetInstance(){
static A a;
return a;
}
};
class Sound : public InstanceTemplate<Sound>
{};
It's not a problem in this limited case, however the full-blown singleton pattern
is surprisingly difficult to design and implement in a generic fashion (otherwise
boost, for example, would definitely provide one).
Disch
Do you mean the same sort of error produced when leaving out #pragma once / #ifndef #endif in the .h when trying to declare a class?
I haven't found any issues while testing the InstanceTemplate but maybe my tests aren't hardcore enough.
Could someone provide an example that would produce an error using the InstanceTemplate?
jsmith
I guess I'm lucky only dealing with my example of code which I know how I'll use down the road. I can see how the template may not be suitable for others.
I'm just wondering for this specific case, with a project of some complexity, would using this sort of design cripple me into a coding mess?
// in b.cpp
void B()
{
Sound& snd = InstanceTemplate<Sound>::GetInstance();
// SURPRISE 'snd' isn't the same object as in a.cpp because the template is instantiated
// seperately in each cpp file.
}
HOWEVER, like I said if you derive from the class then the Sound class instantiates InstanceTemplate<Sound> so you're probably okay.
I'm just wondering for this specific case, with a project of some complexity, would using this sort of design cripple me into a coding mess?
Just off the cuff, one of the limitations of the template-based solution is it only supports default
construction of the singleton. But otherwise, no, the only external interface you have into the
"singleton stuff" is the GetInstance() method, and that will not change regardless of the design.
It's just I'm not sure the problem is solvable generically, which implies that the template-based
solution may not be useful across the board. (Prefer one solution to a problem than N).