C++ Chapter 8.10 : static 정적 멤버 변수

Date:     Updated:

카테고리:

태그:

인프런에 있는 홍정모 교수님의 홍정모의 따라 하며 배우는 C++ 강의를 듣고 정리한 필기입니다. 😀
🌜 [홍정모의 따라 하며 배우는 C++]강의 들으러 가기!


chapter 8. 객체 지향의 기초 : static 정적 멤버 변수

정적 변수 포스팅 참고

🔔 static 멤버 변수란?

모든 객체가 한 메모리를 공유하는 멤버 변수. 객체 별로 각각 할당되는 멤버가 아니라 모든 객체가 공유하는 멤버다.

image

  • 모든 객체가 공유하는 멤버 변수이기 때문에
    • 메모리는 프로그램 시작때부터 차지하고 있으며 메모리에 내내 값이 유지된다.
      • 객체 생성 전에도 메모리 존재
        • 따라서 객체 생성 전에 반드시 미리 초기화를 해주어야 한다.
      • 객체와는 독립적으로 존재한다.
    • 객체 이름으로도 접근이 가능하지만 클래스 이름으로도 접근이 가능하다.
      int Something::s_value = 1;
      
    • s_valuestatic멤버 변수라면 객체1의 s_value 와 객체2의 &s_value주소가 동일하다.
  • 어떤 특정 타입의 모든 객체들의 수 라던지 모든 객체들이 알고 있고 공유할 수 있어야 하는 멤버 변수를 static으로 쓴다.


🔔 static 멤버 변수의 정의

선언과 정의의 구분

  • 이건 단순 선언이다.
    • 컴파일러에게 변수의 정보만을 주며
    • 실제 메모리를 사용하지는 않음
    • 아래 코드는 단순히 static멤버 변수 m_value의 존재를 컴파일러에게 알려주는 것일 뿐이다.
      class Something
      {
      public:
        static int m_value;  // 선언. 메모리를 차지 하지 않는다.
      }
      
  • 이건 정의이다.
    • 실제 메모리가 할당된다
    • 초기화 하는 것도 정의해주는 과정이다.
      • 메모리에 값을 넣으니까.
    • 아래 코드는 static멤버 변수 m_value 의 메모리를 할당해주고 값을 1을 넣어주는 과정이다.
      int Something::m_value = 1;  // 정의. 전역 범위의 메모리를 할당 받는다.
      

static 멤버 변수는 모든 객체가 공유해야 하므로 프로그램 전체 영역에서 메모리 유지가 되야 한다. 따라서 반드시 전역 범위에서 정의 및 초기화를 해주어야 한다.


반드시 전역 범위에서 초기화 해야 한다.

int Something::m_value = 1;

전역 범위에서 자료형이름 클래스이름::static변수이름 = 초기화할값 형식으로 초기화 해준다.

class Something
{
public:
    static int m_value = 1; // 에러 💥 여기서 초기화 불가능
}
  • static 멤버 변수를 저렇게 클래스 내에서 초기화 하면 객체를 생성할 때마다 static멤버 변수 값이 계속 해서 덮어 씌워질 것이다. 왜냐면 모든 객체들이 이 멤버를 공유하기 때문이다.
  • static멤버 변수는 클래스 내에서 선언만 가능하고 정의는 불가능

static멤버 변수는 모든 객체들이 접근해야 하므로 프로그램 시작부터 끝까지 유지되어야 하기 때문에 전역 범위 에서만 정의(초기화)할 수 있다.

  • 따라서 static 멤버 변수는 main 함수는 물론이고 생성자 안에서도 초기화 할 수 없다.
    • 생성자도 static여야 static 멤버 변수를 초기화시킬 수 있는데 C++에서는 static 생성자를 지원하지 않는다.
#include <iostream>

using namespace std;

class Something
{
public:
	static int m_value; // 선언. .
};

int Something::m_value = 1; // 👈👈 전역 범위에서 초기화

int main()
{
    // int Something::m_value = 1;  👈👈 에러!!! 전역 범위에서만 가능. 

    cout << Something::m_value << endl;  // 1 출력 👈👈 객체 생성 전에도 사용 가능
    cout << &Something::m_value << endl;  // 0x601070 출력 👈👈 객체 생성 전에도 사용 가능

    Something st1;
    Something st2;

    st1.m_value = 2;

    cout << st1.m_value << endl;  // 2 출력 
    cout << &st1.m_value << endl; // 0x601070 출력

    cout << st2.m_value << endl;  // 2 출력
    cout << &st2.m_value << endl; // 0x601070 출력

    st2.m_value = 1024;

    cout << Something::m_value << endl; // 1024 출력

    return 0;
}
  • &st1.m_value, &st2.m_value, &Something::m_value 전부 주소가 동일하다
    • 따라서 st1.m_value 값을 바꾸면 st2.m_value, Something::m_value 값들도 동시에 똑같이 바뀐다.
    • 모든 객체는 static변수의 메모리를 공유하기 때문
  • int Something::m_value = 1;
    • 이렇게 전역 범위에서 초기화를 반드시 해주어야 한다.
      • 반드시 전역 범위내에서 정의 해주어야 하기 때문에 main 함수 내에서 int Something::m_value = 1; 해줄 수 없다.


정의 및 초기화는 헤더 파일 내에서는 불가능하다.

헤더 파일과 .cpp 파일로 분리할 때, static 멤버 변수는 반드시 .cpp파일에서 초기화 해준다.

  • static 멤버 변수의 초기화는 헤더파일에선 불가능하다.
    • 여러 곳에서 헤더 파일을 include할 때 마다 static 멤버 변수를 여러번 정의 및 초기화 하는게 될테니까

📜Something.h

class Something
{
public:
	static int m_value; // 클래스 내에선 초기화 불가능
};

int Something::m_value = 1; // 💥에러!💥 헤더 파일 내에선 초기화 불가능

📜Something.cpp

int Something::m_value = 1;


🔔 static const 멤버 변수

static const int m_value;

static const멤버 변수는 클래스 내에서 초기화 하는 것이 가능하다.

  • const이므로 값을 변경하는 것이 불가능하기 때문에 그 모습 그대로를 모든 객체가 공유하기 때문에
    • 한번 초기화 한 이후론 값을 변경하는 것이 불가능하다.
  • 이 같은 경우는 클래스 내부에서 초기화가 가능하다.
    • const는 값이 컴파일 타임에 결정되기 때문에
  • 따라서 헤더파일 내에서도 초기화가 가능하다.
#include <iostream>

using namespace std;

class Something
{
public:
	static const int m_value; // 가능! 🙆‍♀️
};

// int Something::m_value = 1;  👈 const라 클래스 밖에서 기존 값 변경이 불가능

int main()
{
    Something st;

    st.m_value = 1024;  // 👈 💥에러💥 const라서 값 변경 불가

    return 0;
}


🔔 private인 static 멤버 변수 초기화

private한 멤버 변수면 클래스 내에서만 접근이 가능하고 외부에서는 접근이 불가능하기 때문에 초기화는 어떻게 할까 의문이 들었지만, static멤버는 클래스 내부에선 초기화가 불가능하므로 private하더라도 클래스 외부에서 정의가 가능하다.

#include <iostream>

using namespace std;

class A
{
private:  // ⭐⭐⭐
	static int s_value;
};

int A::s_value = 1;    // 👈 private이더라도 전역범위에서 정의 및 초기화 가능

int main()
{
	A a;
	cout << a.s_value << endl;

	A::s_value = 1;  // 👈 💥에러!💥 private이므로 s_value 에접근이 불가능하다.

    return 0;
}


🔔 static 멤버 변수를 클래스 내부에서 초기화 하는 방법

inner-class를 사용하여 클래스 안에 클래스를 하나 더 만들고 그 클래스의 생성자 안에서 초기화를 하는 방법이 있다. 이때 클래스에서 클래스의 클래스 객체를 static 멤버 변수로 선언해주어야 한다.

#include <iostream>

using namespace std;

class Something
{
public:
	class _init // inner class
	{
	public:
		_init()
		{
			s_value = 9876; // s_value 접근 가능.
		}
	};

private:
	static int s_value; 
	static _init s_initializer; 
};
// int Something::s_value = 1234; 
Something::_init Something::s_initializer; 
  • static 멤버 변수인 s_valueSomething 클래스 내에서 간접적으로 초기화 하는 방법
    1. Something 클래스 내에 _init 클래스를 만들어준다.
    2. _init 클래스의 생성자에서 static 멤버 변수인 s_value를 초기화 해준다.
      • 이렇게 간접적으로 클래스 내부에서 초기화하게 됨.
    3. Something 클래스의 static 멤버 변수로 _init 타입의 s_initializer를 추가해준다.
    4. 클래스 외부인 전역 범위에서 Something::_init Something::s_initializer;static 멤버 변수인 s_initializer정의 해준다.
      • 데이터 타입은 Something::_init


🌜 개인 공부 기록용 블로그입니다. 오류나 틀린 부분이 있을 경우 
언제든지 댓글 혹은 메일로 지적해주시면 감사하겠습니다! 😄

맨 위로 이동하기


Cpp 카테고리 내 다른 글 보러가기

댓글 남기기