Static Variable

일반적인 클래스로는 c-style의 콜백을 처리할 수 없다는 것을 알았고, 이는 단순한 대처로는해결하기 힘듬을 알았다. 그렇다면 어떻게 클래스를 사용하면서도, c-style을 유지할 수 있을까?

한 가지 방법으로는 static 변수를 멤버 변수로 사용하는 방법이다. 그러나 이 방법은 그리 유용하지 못하다. 왜냐하면 static 멤버 변수는 클래스를 선언하지 않고도 사용 가능하며, 그 클래스가 모두 공유하는 변수이기 때문에, 사실상 전역 변수이나 다름이 없어지기 때문이다.

우리는 클래스의 멤버 변수가 코드 안에서 자유롭게 선언되기를 (정확하게는 스택/힙 영역에서 메모리 확보가 이루어지기를) 원한다.  한가지 기본적인 대안은, 콜백 함수 내에서 자신이 속한 클래스의 레퍼런스를 가지고 있다가 콜백 함수에서 사용하는 것이다. 이 방법은 나름 설득력이 있어 보인다.

#include <iostream>

// 전역변수 콜백 함수 포인터.
// 어떤 라이브러리 어딘가에 있다고 가정한다.
void (*g_callback)(void) = NULL;

// 우리는 C-Style의 함수가 아닌 class를 필요로 한다.
class cb_class
{
public:
     cb_class() : n(100) {}
    ~cb_class() {}

    // 라이브러리는 이 함수를 필요로 한다.
    // static 키워드를 포함할 때와 그렇지 않을 때를 비교하라.
    static void callback(void)
    {
        cb_class& real = *ptr;

        std::cout << "Our callback function is called.n";        

        std::cout << "member variable n: " << real.n << std::endl;
    }

    static cb_class* ptr;

private:
    int n;
};

cb_class* cb_class::ptr = NULL;

int main(int argc, char** argv)
{
    // 라이브러리에 우리의 콜백 함수를 등록하는 과정이라고 가정한다.
    g_callback = &cb_class::callback;

    // 일반적인 콜백 클래스를 선언한다.
    cb_class cb;
    cb_class::ptr = &cb;

    // g_callback이 우리가 만든 callback을 대신한다.
    // 현재 우리가 만든 main 함수 안에서 호출되고 있으나
    // 이 while문의 구조는 라이브러리 내부 어딘가라고 가정한다.
    int nCount = 3; // 3회 callback 함수를 호출
    while(nCount--)
    {
        g_callback();
    }

    return EXIT_SUCCESS;
}

가장 단순한 형태이지만, 이것은 콜백을 수행하는 스태틱 함수에서 멤버 변수를 사용할 수 있는 방법이 될 수 있다. 그러나 콜백함수의 인자를 넣고 참조하는 방법의 가독성은 좋지 않을 뿐더러, 콜백 함수에서 클래스의 멤버에 아무 제한 없이 접근할 수 있다는 점은 문제로 남아 있다. 이러한 문제는 콜백 클래스와 데이터 클래스를 분리함으로써 해결할 수 있다.

차례로 돌아가기