본문 바로가기

Programing/C/C++/STL

[C++] 멤버 함수포인터 사용하기

출처 : http://teamblog.joinc.co.kr/yundream/95

여러분은 함수포인터를 사용해봤을 것이다. C에서 제공하는 qsort(3)와 같은 함수도 함수포인터를 사용한다.
다음은 qsort(3)을 이용해서 정렬하는 간단한 프로그램이다.

#include <unistd.h>
#include <stdio.h>
#include <stdlib.h>

int compare(const int *one, const int *two)
{
    if (*one > *two)
        return  -1;
    else
        return 1;
}

int a[3] = { 50, 10, 20 };

int main()
{
    qsort(a, 3, sizeof(a[0]), compare);
    print("%d\n", a[0]);
    return 0;
}

qsort 함수는 인자로, 비교에 사용할 함수의 포인터를 받고 있음을 알 수 있다. 만약 함수포인터를 사용하지 않는다면,
비교연산의 종류의 갯수만큼 새로운 qsort함수를 만들어야 될 것이다.
위 코드는 일반적으로 잘 컴파일 되지만, 컴파일러의 특성에 따라서 경고를 발생하거나 컴파일이 안되는
문제가 발생할 수 있다. C 컴파일러에서 컴파일을 한다면 경고를 발생할 것이고,
C++ 컴파일러에서 컴파일 한다면 에러가 발생할 것이다. 이는 이들 두개의 언어가 강타입언어이기 때문이다. C++에서 에러가 발생하는 이유는 일반적으로 C++이 더욱 강하게 타입을 검사하기 때문이다.


qsort 함수는 stdlib.h에 다음과 같이 선언되어 있다.

void qsort(void *base, size_t nmemb, size_t size, int(*compar)(const void *, const void *));

그러므로 타입을 명확히 하는 것으로 문제를 해결할 수 있다. 이제 C 컴파일러건 C++ 컴파일러건 간에 경고메시지 하나 없이 깔끔하게 컴파일 될 것이다. 

qsort(a, 3, sizeof(a[0]), (int (*(const void *, const void *))compare);

 

클래스 에서의 함수 포인터 사용

다음은 C 스타일의 함수포인터다.
#include <iostream>

using namespace std;

void apple(void)
{
    cout << "apple" << endl;
};

void berry(void)
{
    cout << "berry" << endl;
}

int main()
{
    void (*fptr)(void);
    fptr = apple;
    fptr();
    fptr = berry;
    fptr();
}
위의 코드를 C++ 스타일로 바꾸어 보았다. 함수포인터를 이용해서 멤버변수에 접근함을 알 수 있다.
#include <iostream>

using namespace std;

class fruit
{
    public:
        void apple() { cout << "apple" << endl; }
        void berry() { cout << "berry" << endl; }
};

int main()
{
    fruit x, *y;
    void (fruit::*f)(void);

    y = new fruit;
    f = &fruit::apple;
    (x.*f)();

    f = &fruit::berry;
    (y->*f)();

    delete y;
}
C++에서의 멤버포인터를 위한 연산자를 따로 제공하다. '.*'을 사용해서 멤버함수를 포인팅할 수 있다.
호출은 '->*'를 이용하면 된다.

이제 qsort() 함수에 정렬연산을 위해서 멤버함수 포인터를 넘겨보도록 하자.
#include <stdlib.h>
#include <iostream>

using namespace std;

class fruit
{
public:
    fruit() { f = &fruit::compare; }
    int (fruit::*f)(const int*, const int*);
    int compare(const int *one, const int *two)
    {
        return ( (*one == *two) ? 0 : *one > *two );
    }
} apple;

int funcptr(const void* one , const void* two)
{
    return ( (apple.*apple.f)( (const int *)one, (const int *)two ) );
};

int a[3] = { 3, 2, 1 };

int main()
{
    int i;

    cout << "before ";
    for( i=0; i < 3; i++ ) cout << a[i] << "  ";

    cout << endl;
    qsort(a, 3, sizeof(a[0]), funcptr );

    cout << "after ";
    for( i=0; i < 3; i++ ) cout << a[i] << "  ";

    cout << endl;
    return 0;
}

 

friend와 static 에서의 함수포인터 사용

이제 friend와 static 멤버함수에 접근하는 방법을 알아보자. 다음은 friend 함수에 접근하는 방법이다.
#include <iostream>

using namespace std;

class fruit
{
public:
    void apple() { cout << "apple" << endl; }
    void berry() { cout << "berry" << endl; }
    
    friend void cherry(void (fruit::*func)(), fruit x) { (x.*func)(); }
}

int main()
{
    fruit x;
    void (fruit::*f)(void);
    f = &fruit::apple;
    (x.*f)();
    f = &fruit::berry;
    cherry(f,x);
}

다음은 static 멤버함수에 접근하는 방법이다.
#include <iostream>

using namespace std;

class fruit
{
public :
    void apple() { cout << "apple" << endl; }
    void berry() { cout << "berry" << endl; }
    
    static void cherry(void(fruit::*func)(), fruit x) { (x.*func)(); }
};

int main()
{
    fruit x;
    void (fruit::*f)(void);

    f= &fruit::apple;
    (x.*f)();

    f = &fruit::berry;
    x.cherry(f,x);

    return 0;
}
클래스에 임베디드된 함수포인터를 호출하는 예제코드다.
#include <iostream>

using namespace std;

class fruit
{
public:
    void (fruit::*ff)(void);
    void apple() { cout << "apple" << endl; }
    void berry() { cout << "berry" << endl; }
};

int main()
{
    fruit x;
    void (fruit::*f)(void);
    
    f = &fruit::apple;
    x.ff = &fruit::berry;
    (x.*f)();
    (x.*x.ff)();
    
    return 0;
}

템플릿에서의 함수 포인터 사용

템플릿에서의 사용도 가능하다.
#include <iostream>

using namespace std;

template<class T>
class alpha
{
    T data;
    public :
        alpha(T x) {data = x;}
        T show() {cout << data << endl;}
};

int main()
{
    int (alpha<int>::*ifunc)();
    float (alpha<float>::*ffunc)();

    alpha<int> a(123);
    alpha<float> b(456.78);

    ifunc = a<int>::show;
    ffunc = a<float>::show;

    (a.*ifunc)();
    (b.*ffunc)();

}

'Programing > C/C++/STL' 카테고리의 다른 글

[C++]C++의 메모리 영역  (0) 2009.08.27
[C/C++]메모리 영역 구분  (0) 2009.08.27
[C++] explicit 키워드  (0) 2009.07.14
Source Code 수행속도 측정하는 방법  (0) 2009.06.30
OpenMP 라고 아십니까??  (0) 2009.06.30