Hello,

I am using a singleton pattern, which works fine. But when I decided to have a singleton of a nested class that is privately declared.

class A : public CSingletonTmpl<A>
{
	class B : public CSingletonTmpl<B>
	{
	};
};
A* CSingletonTmpl<A>::s_Singleton = NULL;
A::B* CSingletonTmpl<A::B>::s_Singleton = NULL;

The last line causes a compile time error: 'A::B' : cannot access private class declared in class 'A'.

I understand that class B is private and if I do not want to make it public, what are my options?

I do know that if I do not use CSingletonTmpl, but declare s_Singleton directly as a member of B, then A::B::s_Singleton can be instantiated. This seems strange to me. Why should not I be able to access s_Singleton if it is in the publicly derived class for B?

Thanks.

Recommended Answers

All 8 Replies

Hello,

I am using a singleton pattern, which works fine. But when I decided to have a singleton of a nested class that is privately declared.

class A : public CSingletonTmpl<A>
{
	class B : public CSingletonTmpl<B>
	{
	};
};
A* CSingletonTmpl<A>::s_Singleton = NULL;
A::B* CSingletonTmpl<A::B>::s_Singleton = NULL;

The last line causes a compile time error: 'A::B' : cannot access private class declared in class 'A'.

I understand that class B is private and if I do not want to make it public, what are my options?

I do know that if I do not use CSingletonTmpl, but declare s_Singleton directly as a member of B, then A::B::s_Singleton can be instantiated. This seems strange to me. Why should not I be able to access s_Singleton if it is in the publicly derived class for B?

Thanks.

please post your singleton implementation

please post your singleton implementation

Here it is:

#include <boost/noncopyable.hpp>
template<typename T> class CSingletonTmpl : private boost::noncopyable
{
protected:
	/// Pointer to the singleton object
	static T* s_Singleton;
	/// Constructor
	CSingletonTmpl( void )
	{
		assert( !s_Singleton && "Singleton is already initialized, only one initialization is allowed");
#if defined( _MSC_VER ) && _MSC_VER < 1200	 
		int offset = (int)(T*)1 - (int)(Singleton <T>*)(T*)1;
		s_Singleton = (T*)((int)this + offset);
#else
		s_Singleton = static_cast< T* >( this );
#endif
	}
public:
	/// Destructor
	virtual ~CSingletonTmpl(void)
	{
		s_Singleton = 0;
	}
	/// Returns reference to the singleton object
	static T& GetSingleton(void)
	{
		assert(s_Singleton && "Singleton should be created before it can be accessed");
		return(*s_Singleton);
	}
	/// Returns pointer to the singleton object
	static T* GetSingletonPtr(void){return s_Singleton;}
};

I don't know anything about a "singleton pattern" but my guess is this is one part of your problem:

protected:
	/// Pointer to the singleton object
	static T* s_Singleton;

While a protected status is less-restrictive than private. It simply means that inherited objects can now have access to it, but external code (which yours appears to be) still can not.

There seems to be another issue, but I can't put my finger on what it is.... Something isn't reading right to me... It may just be my naivety RE: singleton pattern...

[edit]
This link may help...IDK... It seems to suggest using a static function to return a reference to the static object as part of the initialization.

I don't know anything about a "singleton pattern" but my guess is this is your problem:

protected:
	/// Pointer to the singleton object
	static T* s_Singleton;

While a protected status is less-restrictive than private. It simply means that inherited objects can now have access to it, but external code (which yours appears to be) still can not.

I would agree with you, but the compiler complains about A::B and not about A::B::s_Singleton, which implies that it does not even go all the way there. But to test it, I made s_Singleton public and it did not change the error.

After thinking a little more I realized that the problem must be with this statement:

CSingletonTmpl<A::B>

. A::B can not be accessed by anything other than A. But if I use

friend CSingletonTmpl<B>;

after B declaration, then the code compiles just fine. Any suggestions on why this may not be a good practice?

IDK why, but I didn't see your last 2 posts, I don't think my browser was refreshing correctly. I added a link to my previous post that may be useful.

I've only read about friends, I really know nothing about them... I do know that you need to use them sparingly. The link I provided does not mention anything about them...

With template code you have to be careful on relying on the compiler. You can have broken code that the compiler does not complain about. Until you instantiate a class you cannot be sure that you have no conflicts.

Your singleton method seems a little unusual to me it may have something to do with the boost library with which I am not familiar.

If you use a static factory method it does not matter if the constructor is called more than once, this is why it is declared private/ protected. Otherwise you can have just a static int check > 0

//singleton factory method
class highlander
{
public:
//factory method get the one and only 
static highlander * create()
{
 if(pointer == 0)
 {
  //may want try catch to ensure new doesn't fail
   pointer = new highlander();
 }
return pointer;
}
private:
highlander() {//does nothing}

static highlander * pointer;
}

there are several singleton approaches and it depends on what you want
a single global
avoiding duplicates
just one at one time
one per template

But templating singleton there are several problems that might be created, your constructor looks odd to me as you are casting
this to T* but this does not inherit from T with singleton it is important to know what you are using it for.

Template classes are tricky to use with inheritence and you should only use them when you are sure that they are needed as there will normally be several design options and I have found that static template and virtual often play badly together.

After thinking a little more I realized that the problem must be with this statement:

CSingletonTmpl<A::B>

. A::B can not be accessed by anything other than A. But if I use

friend CSingletonTmpl<B>;

after B declaration, then the code compiles just fine. Any suggestions on why this may not be a good practice?

Line 8 should be:

A::B* A::B::CSingletonTmpl<B>::s_Singleton = NULL;

which reflects the type of the singleton pointer, and the access required to reach it through A, B, and CSingletonTmpl<B>, I think.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.