Software Development/C, C++

[C++] C++에서의 static

huiyu 2018. 12. 30. 08:52

C언어에서의 static

 - 전역변수에 선언된 static의 의미
  : 선언된 파일 내에서만 참조를 허용

 - 함수 내에서 선언된 static의 의미
 : 한번만 초기화되고, 지역변수와 달리 함수를 빠져나가도 소멸되지 않는다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <iostream>
 
using namespace std;
 
void Counter()
{
  static int cnt;
  cnt++;
  cout<<"Current cnt: "<<cnt<<endl;
}
 
int main(void)
{
  for(int i=0; i<10; i++)
    Counter();
  return 0;
}
cs

 [출력결과]
Current cnt : 1
Current cnt : 2
Current cnt : 3
Current cnt : 4
Current cnt : 5
Current cnt : 6
Current cnt : 7
Current cnt : 8
Current cnt : 9
Current cnt : 10

-> static 변수는 전역변수와 마찬가지로 초기화하지 않으면 0으로 초기화, 초기화는 딱 한번만 실행된다.
  즉, cnt는 Counter함수가 호출될때마다 새롭게 할당되는 지역변수가 아니다.


static 멤버변수(클래스변수)

 - static 멤버변수는 '클래스 변수'라고도 한다. 일반적인 멤버변수와 달리 클래스당 하나씩만 생성되기 때문이다.

1
2
3
4
5
6
7
8
9
10
11
12
13
class SoSimple
{
private:
  static int simObjCnt;    // static 멤버변수, 클래스 변수
public:
  SoSimple()
  {
    simObjCnt++;
    cout<<simObjCnt<<"번째 SoSimple 객체"<<endl;
  }
};
 
int SoSimple::simObjCnt=0;  //static 멤버변수의 초기화\
cs

 -> 위의 코드에 선언된  static 변수 simObjCnt는 SoSimple객체가 생성될 때마다 함께 생성되어 객체별로 유지되는 변수가 아니다.
  객체를 생성하건 생성하지 않건, 메모리 공간에 딱 하나만 할당되어 공유되는 변수이다.

1
2
3
4
5
6
7
int main(void)
{
  SoSimple sim1;
  SoSimple sim2;
  SoSimple sim3;
  ....
}
cs

다음과 같이 sim1, sim2, sim3 객체가 static 변수 simObjCnt를 공유하는 구조가 된다.

- sim1, sim2, sim3 객체의 멤버함수에서는 simObjCnt에 멤버변수에 접근하듯이 접근이 가능하다.
 하지만 simObjCnt가 객체 내에 존재하는 것은 아니다. 이 변수는 객체 외부에 있다. 다만 객체에 멤버변수처럼 접근할 수 있는 권한을 준 것이다.

- 생성 및 소멸의 시점도 전역변수와 동일하다.

* simObjCnt를 별도로 초기화하고 있는 이유?
 - 만약 static변수를 생성자에서 초기화하면, 객체가 생성될때마다 변수 simObjCnt는 0으로 초기화되기 때문


* static 멤버변수 접근방법

  simObjCnt를 public으로 선언하면 클래스의 이름, 객체의 이름을 통해 어디서든 접근이 가능하다.  

1
2
3
4
5
6
7
8
9
int main(void)
{
  SoSimple sim1;
  SoSimple sim2;
 
  cout<<sim1.simObjcnt<<endl;
  cout<<sim2.simObjcnt<<endl;
  cout<<SoSimple::simObjCnt<<endl;
}
cs

 -> 위의 출력하는 세문장은 동일한 출력을 한다. 
  그중 sim1, sim2의 출력은 멤버변수에 접근하는 것과 같은 오해를 일을킨다. 
  따라서 public static멤버에 접근할 땐, SoSimple::simObjCnt와 같이 클래스의 이름을 이용하여 접근하는 것이 좋다.


static 멤버함수

  static 멤버함수 역시 그 특성이 static 멤버변수와 동일하다. 따라서 위에서 설명한 특성이 그대로 적용된다.
  - 선언된 클래스의 모든 객체가 공유
  - public으로 선언이 되면, 클래스의 이름을 이용해서 호출이 가능
  - 객체의 멤버로 존재하는 것이 아니다.

*static멤버함수는 객체의 멤버로 존재하지 않기 때문에 다음의 코드는 컴파일 에러가 발생

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
class SoSimple
{
private:
  int num1;
  static int num2;
 
public:
  SoSimple(int  n): num1(n)
  {}
  static void Adder(int n)
  {
    num1+=n; // 컴파일 에러발생
    num2+=n;
  }
};
 
int SoSimple::num2 = 0;
cs

 -> 객체의 멤버가 아니기 때문에 멤버변수에 접근이 불가
 -> 객체 생성 이전에도 호출이 가능하다. 객체 생성 이전에 멤버변수에 접근하는 것은 불가

* static 멤버함수 내에서는 static 멤버변수와 static멤버함수만 호출이 가능


const static 멤버

 클래스에 선언된 const 멤버변수(상수)의 초기화는 이니셜라이저를 통해야만 했다. 그러나 const static으로 선언된 멤버변수(상수)는 선언과 동시에 초기화가 가능하다.

1
2
3
4
5
6
7
8
class CountryArea
{
public:
  const static int RUSSIA      = 1707540;
  const static int CANADA      = 998467;
  const static int CHINA       = 957290;
  const static int SOUTH_KOREA = 9922;
};
cs


[참고자료]

윤성우 열혈 C++ 프로그래밍 06-3 C++에서의 static

728x90