C++ Chapter 8.11 : static 정적 멤버 함수

Date:     Updated:

카테고리:

태그:

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


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

🔔 static 멤버 함수란?

  • staitc 멤버 변수처럼
    • 객체 이름은 물론이고 클래스 이름만으로도 접근이 가능하다.
    • 객체와 독립적이다. 객체 생성과 상관 없다.
      • 따라서 멤버 변수는 객체가 생성되야 메모리를 할당받기 때문에 static 멤버 함수 내에서는 멤버 변수를 사용할 수 없다.
      • 그러나 미리 전역에서 메모리가 할당되는 static 멤버 변수는 사용이 가능하다.
class Something
{
private:
    int noramal_value = 99;  // 일반 멤버 변수
    static int static_value; // static 멤버 변수

public:
    static void Func()     // ⭐ static 멤버 함수
    {
        int a = 1024;      // Func()내의 일반 지역 변수 
        cout << a << endl;

        // cout << noramal_value << endl; 👈👈 💥에러!!!💥 일반 멤버 변수는 사용할 수 없다. 

        cout << static_value << endl; // static 멤버 변수는 사용 가능
    }
};

int Something::static_value = 777;

int main()
{
    Something::Func();  // 객체 생성 없이 바로 클래스 이름으로 호출 가능

    /* 👆 1024와 777을 출력한다. */

    return 0;
}


🔔 static 멤버 함수를 사용하는 이유

객체 생성 여부와 상관없이 바로 클래스 이름으로 접근하고 싶을 때 사용하지만 주로 private인 static 멤버 변수에 접근하려 할 때 많이 쓰인다.

  • staitc 멤버 변수는 모든 객체들이 사용하고 공유해야하는데 private이라면 외부에서 직접 접근하고 사용할 수가 없다.
    • private인 멤버 변수들은 멤버 함수들에서만 접근이 가능하다는 특징이 있다.
  • static 멤버 함수 를 통해서 privatestaitc 멤버 변수 에 간접 접근할 수 있도록 구현할 수 있다.
    • 마치 getter, setter 접근함수처럼!
class Something
{
private:
    static int static_value; // private한 static 멤버 변수

public:
    static int getValue()     // ⭐ static 멤버 함수
    {
        return static_value;  
    }
};

int Something::static_value = 777;

int main()
{
    // cout << Something::static_value << endl;  👈👈 💥에러!💥 private이므로 직접 접근 불가능

    cout << Something::getValue() << endl;   // 777 출력. 클래스 이름으로 호출했을 때. 

    Something s;
    cout << s.getValue() << endl;  // 777 출력. 객체 이름으로 호출했을 때. 

    return 0;
}

이처럼 private한 staitc 멤버 변수를 직접 접근할 수는 없지만 static 멤버 함수 getValue()를 통하여 간접적으로 staitc 멤버 변수를 리턴받을 수 있다.


🔔 static 멤버 함수는 this 포인터를 사용할 수 없다.

  • this 포인터는 객체인 자기 자신의 주소, 즉 객체의 주소를 담고 있기 때문에 객체가 생성되야지만 사용할 수 있다.
    • static 멤버 함수는 객체들의 생성과 무관하며 언제 어디서든 클래스 이름으로도 접근이 가능해야 하기 때문에
    • static 멤버 함수 내부에서는 this 포인터를 사용할 수 없다.
    • static 멤버 함수 내부에서 일반 멤버 변수를 사용할 수 없었듯이.
    • 이에 더해 this포인터로 접근할 수 있는 모든 것을 하지 못 한다.
      • 같은 객체 내의 멤버 변수나 멤버 함수는 접근하지 못한다. 눈에 보이지 않아도 이들을 접근할 땐 this->가 숨어있는 것이나 마찬가지기 때문에.
class Something
{
private:
    static int static_value; // static 멤버 변수

public:
    static int getValue()     // ⭐ static 멤버 함수
    {
        return this -> static_value;  // 💥에러💥 
    }

    int temp()  // ⭐ 일반 멤버 함수
    {
        return this -> static_value; // 문제 없다.
    }
};
  • static 멤버 함수인 getValue()에선 this를 사용할 수 없다.
  • 일반 멤버 함수인 temp()에선 this를 사용할 수 있다.


멤버 함수 포인터

함수 포인터 포스트에서 일반 함수는 함수 이름에 함수의 주소값이 들어있다는 것을 공부했었다. 그러나 멤버 함수의 포인터는 조금 다르다.

멤버 함수의 포인터& 클래스이름 :: 함수이름 으로 접근해야 한다.

class Something
{
public:
    int temp() { return 1; }
};

int main()
{
    Something s1;
    Something s2;

    int (Something::*fptr_1)() = s1.temp;  // 💥에러💥
    int (Something::*fptr_2)() = &Something::temp;  // 문제 없다.
}
  • int (Something::*fptr_1)() = s1.temp;
    • 💥에러💥
      • 멤버 함수의 포인터는 이렇게 s1.temp 함수 이름으로 접근하면 안된다.
  • int (Something::*fptr_2)() = &Something::temp;
    • 멤버 함수의 포인터는 이렇게 & 클래스이름 :: 함수이름으로 &와 클래스 이름으로 접근해야 한다.
  • 이유
    • 멤버 변수는 각 객체들마다 따로 메모리를 가져 주소가 다르지만
    • 멤버 함수객체마다 함수 메모리를 따로 갖는 방식이 아니기 때문이다.
      • 멤버 함수는 어딘가 한군데에 저장되어 있고 각 객체마다 그 공간에 동일하게 접근하여 각자의 다른 데이터로 사용하는 방식이다.
      • 따라서 일반 함수의 주소와는 다르게 멤버 함수의 주소를 받아와야 한다.
        • 그럴려면 속해있는 클래스가 어디인지 알려주어야 한다. &Something::

함수 포인터로 함수 실행하기 : 일반 멤버 함수

temp()는 Something 클래스의 일반 멤버 함수라고 하자.

Something s;

int (Something::*fptr_1)() = &Something::temp;
cout << (s.*fptr_1)() << endl;   // 함수 포인터로 s 객체의 temp 함수 실행
  • int (Something::*fptr_1)()
    • 포인터 선언시 Something::를 꼭 붙여주어야 한다.
  • 함수 포인터로 일반 멤버 함수를 실행할 때는 꼭 (s.*fptr_1)() 처럼 객체로 접근해 주어야 한다.
    • fptr_1은 객체에 종속되는 일반 멤버 함수를 참조하고 있기 때문에 단독으로 호출할 수 없기 때문이다.
    • 멤버 함수 포인터는 객체의 내용물을 참조하기 때문에 (객체.*멤버함수포인터)(매개변수)로 사용해야 한다.
      • 포인터로 객체를 참조하고 있다면 (객체포인터->*멤버함수포인터)(매개변수)

함수 포인터로 함수 실행하기 : static 멤버 함수

getValue()는 Something 클래스의 static 멤버 함수라고 하자.

Something s;

int (*fptr_2)() = &Something::temp;
cout << fptr_2() << endl;   // 함수 포인터로 s 객체의 temp 함수 실행
  • int (*fptr_2)()
    • static 멤버 함수는 객체와 무관하게 연산이 이루어 지기 때문에 일반 함수 포인터로 취급 받는다.
      • 따라서 포인터 선언시 Something:: 을 떼고 일반 함수처럼 int (*fptr_2)()로만 선언해준다.
  • fptr_2()
    • 일반 함수 포인터로 취급되기에 이렇게 단독 호출할 수 있다.


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

맨 위로 이동하기


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

댓글 남기기