static 멤버함수는 this객체를 받지않는다.(static은 사용범위가 지정되어 있기때문이다. static멤버함수의 경우 사용범위는 클래스가 생성한 객체가아닌 클래스 전반적으로 사용하는 함수, 다시말하면 클래스의 static 멤버를 다루는 함수라 봐도 좋다) 때문에 static 멤버함수는 클래스형에 의해서 호출되는 함수다. 객체를 통해 호출하려고해도 그 객체의 클래스형만 살펴본 후 맞다면 호출한다.
static이 아닌 멤버의 경우 함수내에서 this의 호출을 통해 이루어진다. 기본적으로 this가 전달된후 컴파일러상에서 this로 접근한다.
그렇기때문에 static 멤버변수가 아닌 변수를 접근하는건 불가능하다.
또산 static 선언은 목적파일 링크시에 알리지않는다는 뜻이다.(선언된 파일 내부에서만 사용하겠다는의미)
static 멤버함수는 자신이속한 클래스명을통해 객체생성없이 호출될수있다.(객체를통해 생성하는것도 가능하지만 자제하길바란다.(코드의 가독성이 떨어지기때문이다)
이런 static의성질을 통해 다음과같이 싱글톤을 디자인해본다.
객체생성을 static 멤버함수를 통해서 해보면 어떨까?
함수내부에서 객체를 생성했으므로 받아주는 자신이 속한 클래스 타입의 객체변수(포인터)가 있어야한다.
좀더 생각해보자.
그러면 static 멤버함수 내부에서 객체를 생성하고 그것을 받아주는 멤버변수를 static으로 두면
함수호출만으로 객체생성이된다.
함수호출만으로도 객체가 생성된다. 편리하다.
예를들어 cocos2d-x에선 매크로를 사용하여 다음과 같이 사용한다.
#define CREATE_FUNC(__TYPE__) \
static __TYPE__* create() \
{ \
__TYPE__ *pRet = new __TYPE__(); \
if (pRet && pRet->init()) \
{ \
pRet->autorelease(); \
return pRet; \
} \
else \
{ \
delete pRet; \
pRet = NULL; \
return NULL; \
} \
}
자신이 속한 클래스 타입을 반환하는 create() satic 멤버함수를 선언함으로서
자신이 속한 클래스의 init() 함수의 호출과 더불어 객체의 생성과 추가적인 작업 autorelease() 까지 하였다.
이 작업은 가독성을 높여주고 내부적으로 autorelease() 까지 해주므로 메모리 관리까지 덩달아 해주게 한다. 하지만 객체포인터의 할당을 위해서 외부에서 객체포인터를 추가로 한번 더 설정하여 전달의 전달을 하는 셈이 된다. 아무래도좋다.
이 경우 static 멤버함수의 용도는 객체생성을하면서 추가적인 처리를 한번에 하기 위한 용도로 사용했다고 결론내리자. 객체생성만 하는 용도라면 궂이 이렇게 하지않아도 상관없을 것 같다.
그럼 다음으로 넘어가서
싱글톤에 대해서 고찰을 해보자.
싱글톤 말그대도 클래스 인스턴스 하나만 생성하기 정도?
다음의 작업이 필요하다.
(객체 인스턴스를 하나만 생성하기 - static 함수내에서 처리)
(외부에서 new 키워드로 생성 못하게 하기 - 생성자의 private)
static 함수로 객체를 생성하는경우 몇번이든 호출해도 상관없지만,
외부에서 new 키워드를 사용시 private에 생성자를 선언하게되면 에러가난다.
다음의 코드를보자.
#include <iostream>
using namespace std;
class A
{
A(){}
static A* single_ton;
public:
int num;
static A* get_Instance();
};
A* A::single_ton;
A* A::get_Instance() {
if(single_ton==NULL)
single_ton = new A();
return single_ton;
}
int main(int argc, char *argv[])
{
A* object1 = A::get_Instance();
object1->num = 10;
A* object2 = A::get_Instance();
cout<<object1->num<<endl;
cout<<object2->num<<endl;
}
main부분에 객체를 두번 생성했다.
하지만 생성된 객체는 처음 생성된 객체뿐이고 객체포인터 둘다 처음생성된 객체를 그리킨다.