웹서핑 조금만 해도 나오는 싱글턴 패턴 소스.
평소처럼 사용하다가 싱글턴 클래스 상속과 싱글턴을 상속받은 부모 클래스를 다시 자식 클래스가
상속을 받아서 쓰는부분에 대해 궁금함이 생겼다.

일반적인 싱글턴 소스들
template< class T >
class CLmSingleton
{
public:
	static T	*getInstance() {
		if( !s_pInstance ) s_pInstance = new T();
		return s_pInstance;
	}
	static void	releaseInstance() {
		if( s_pInstance ) { delete s_pInstance; s_pInstance = NULL; }
	}

protected:
	static T *s_pInstance;
};

template< class T > T *CLmSingleton< T >::s_pInstance = 0;

//-------------------------------------------------------------- template< class T > class CLmSingleton2 : private T { public: static T* getInstance() { // if use in multi-thread env, should add lock here. static CLmSingleton2<t> s_Instance; return& s_Instance; } protected: CLmSingleton2() {} virtual ~CLmSingleton2() {} }; #define SINGLETON(p) CLmSingleton2<p>::getInstance()

상단에 있는 싱글턴 소스는
class A : public CLmSingleton<A>
{
public:
	A() {}
	virtual ~A() {}

	int a;
};

A testClass;			// 일반적인 정적 변수 선언이 가능.
testClass.a = 99;		// 이것은 단순히 testClass 라는 클래스 멤버변수의 값만 바뀐다.
A* pA0 = testClass.getInstance(); // pA0의 멤버변수 a의 값은 쓰레기 값
A* pA1 = A::getInstance();
A* pA2 = CLmSingleton<A>::getInstance();
// pA0, pA1, pA2 세 포인터의 주소는 동일하다.
pA2->a = 98;			// pA0, pA1, pA2의 멤버변수 a가 전부 갱신됨.

testClass 와 포인터들은 다른 주소를 갖는다. 다만 testClass.getInstance() 로 불러오는 인스턴스만은 동일하다.
각각의 인스턴스는 동일하지만 ( testClass != 포인터 ) 이기 때문에 싱글턴이라 부르기 어렵다.
또한, 싱글턴의 특징 중 하나인 외부로 공개하지 않는 생성자와 소멸자가 public이다.
결국, 저 클래스는 실수로라도 정적 변수로 선언을 하게 된다면 나중에 문제가 커질 가능성이 있다.

혹시나 해서 생성자와 소멸자를 protected 와 private로 했는데, 생성자에 접근을 하지 못해 컴파일 에러가 뜬다.


두번째 테스트로 상속을 받지 않고 싱글턴을 적용해 보았다.
class B
{
public:
	B() {}
	virtual ~B() {}

	int b;
};

B* pb0 = B::getInstance(); // 상속을 받지 않았으므로 B에는 getInstance()란 메소드가 없어 오류
B* pb1 = CLmSingleton<B>::getInstance(); // B 클래스라는 새로운 인스턴스 생성 성공.


마지막 테스트는 상단 소스중 CLmSingleton2 로 했다.
class C
{
public:			// protected 도 가능
	C() {}
	virtual ~C() {}

	int c;
};

class C : public CLmSingleton2<C> 로 선언 자체가 안된다. 소스를 보면 서로가 서로를 상속 받는 구조가 되어버린다.

두번째 싱글턴의 경우, 그 특징은 사용하려 명시한 클래스의 자식클래스로 상속이 된다. 첫번째는 싱글턴 자체가 부모클래스이고 사용하고 싶은 클래스는 자식클래스로 상속을 시키는 구조다.

이 싱글턴은 단지 아래 방법만이 가능하다.
C* pc0 = SINGLETON(C);
C* pc1 = SINGLETON(C);

두번째 싱글턴의 경우 클래스 생성자가 public이든 protected든 인스턴스가 생성이 된다. protected인데 생성이 되는 이유는 싱글턴이 부모의 생성/소멸자를 상속을 받았기에 내부에서는 부모를 참조할 수 있기 때문이다. private의 경우 생성/소멸자를 상속 시키지 않아 컴파일 에러가 난다.

//----------
그리고 두 싱글턴의 차이를 보자면 첫번재는 동적 인스턴스이다. 가져올때 없으면 new로 할당을 하고 존재한다면 이미 만들어진 인스턴스를 가져온다. 하지만 소멸자는 불리지 않아 인스턴스가 제대로 지워졌는지 확인이 안된다.
아니면 releaseInstance()를 호출하는 수 밖에 없다.

하지만 두번째 싱글턴은 정적 인스턴스이기 때문에 클래스 자체가 파괴가 되거나 프로그램이 종료가 된다면 메모리를 반환을 한다. 메모리 해제를 할 필요가 없다는 것이다.
그리고 첫번째 싱글턴처럼 인스턴스를 생성할 때 여러 방법이 불가능하다. 싱글턴 생성이나 인스턴스를 가져옴에 있어 통일성이 있다.
만약, 첫번째 싱글턴처럼 이렇게 만드나 저렇게 만드나 똑같은 인스턴스가 나온다면 인스턴스를 가져올 때 통일적이지 않아 나중가면 햇갈릴 가능성이 있는 것이다.

개인적으로 두번째 싱글턴이 좋다.