static 키워드를 붙일수 있는 곳은 함수, 변수, 클래스의 멤버 등 여러가지에 사용이 가능한데, 이때 static 키워드는 사용되는 문맥에 따라 여러 특징을 가진다.
함수 내부에서 선언된 지역 변수에 static 키워드를 붙이면, 이 변수는 함수가 종료되더라도 여전히 값을 유지한 채 메모리 공간에 남아있게 된다. 하지만 지역 변수의 특징은 유지 되어서 사용 범위는 해당 지역 변수가 선언된 함수 내부로 한정된다. 다음은 사용 예시이다.
int StaticSample(){
static int num = 0; // static 함수는 변수를 초기화 하지 않으면 0으로 초기화 된다.
num++;
std::cout << "Static num: " << num << std::endl;
}
int main(){
for(int i = 0; i < 5; i++){
StaticSample();
}
}
위 코드를 실행하면 결과는 다음과 같을것이다.
Static num: 1
Static num: 2
Static num: 3
Static num: 4
Static num: 5
num 변수는 함수 내부에서 선언한 지역 변수임에도 불구하고 함수가 반환되어도 여전히 값을 저장하고 있다는 것을 알수있다.
전역 변수 혹은 함수에 static 키워드를 붙이게 되면, 해당 전역 변수 또는 함수가 선언된 파일 내부에서만 사용 할 수 있도록, 사용 범위를 한정한다. 즉, internal linkage를 가진다. static 키워드가 붙은 함수와 전역 변수는 다른 파일에서는 사용 할 수 없다.
클래스의 static 멤버 변수: 클래스의 멤버 변수가 static으로 선언된다면, 모든 해당 클래스의 객체가 하나의 static 변수를 공유하게 된다. 즉, 클래스의 객체가 몇개가 생성되든, static 변수는 공통으로 하나만 존재한다. 해당 변수는 클래스이름::변수이름 으로 접근 가능하다.
클래스의 static 멤버 함수: 클래스의 함수가 static 키워드로 선언 되었다면, 해당 함수의 소유권이 클래스 객체가 아닌 클래스 자체에 있다. 즉, 해당 함수는 클래스 자체에 속한다는 의미이다. 그렇기 때문에, 객체마다 각각 지니는 non-static 멤버 변수와 함수를 사용하거나 호출 할 수 없다. 이는 static 멤버 함수의 제약 사항인데, non-static 멤버 함수와 변수는 항상 객체 인스턴스에 속해서 연결되어있기 때문에 클래스 자체에 귀속되는 static 멤버 함수는 이들을 사용할 수 없다. 해당 함수는 클래스이름::함수이름() 으로 호출 가능하다.
이러한 제약 사항은 static 멤버 함수의 장점이다. 왜냐하면, non-static 멤버 변수 혹은 함수가 호출되기 위해서는 객체 인스턴스 자신을 가르키는 this 포인터에 의해 호출이 가능한데, static 멤버 함수와 변수는 객체 인스턴스가 존재하지 않아도 호출이 가능하기 때문이다.
이러한 특징들로 인해서 클래스의 static 멤버는 싱글톤 디자인 패턴을 구현할때 사용된다.