티스토리 뷰

1. 함수의 원형

본격적으로 내용을 다루기에 앞서 함수 포인터의 원형과 포인터의 대상이 될 함수와의 원형은 같아야 한다.
이 점은 일반 서적에서 다루고 있는 내용이라 다 알 것이라고 생각되므로 함수의 원형에 대하여 간단하게
Q/A 식으로 짚고 넘어가겠다. 이해가 안되면 무조건 외우는 것도 한가지 방법이라고 생각됨.
마지막으로 함수 포인터는 함수가 아니라 원하는 함수의 주소를 담고 있는 변수이다. 근본적으로는 포인터
(변수 포인터)에 다른 변수의 주소를 넣는 것과 별로 다를 것이 없다. 다만 함수 포인터의 경우는 변수의
주소가 아닌 함수의 주소라는 점만 다를 뿐이다.

int a;
char c[5];
float* f;
"Hello, World"

Q) 위의 코드에서 a, c, f,
"Hello, World"의 원형은?
A)
int, char [], float *, const char *

만일 이 문제들을 못맞추었다면 다시 한번 책을 속독하기를 권함.

void foo();


const char* bar(int num);


class MyClass {
public:
   
void Func1(const string& txt);
   
static void Func2(const string& txt);
};

Q) foo, bar, MyClass::Func1, MyClass::Func2의 원형은?
A)
void (*)(), const char* (*)(int), void (MyClass::*)(const string&), void (*)(const string&)


2. 함수 포인터(전역 함수 포인터) / 멤버 함수 포인터

가. 어떻게 정의/선언하고 사용하는가?

    함수 포인터의 대상이 되는 함수의 원형을 적고 괄호안의 * 연산자의 뒤에 원하는 이름을 붙여서 사용.
    (괄호가 있는 이유는 없을 경우 함수의 리턴형이 * 연산자에 의해 원래 리턴형의 포인터로 처리되기
    때문에, 강력한 우선 순위를 가지는 괄호로 함수 포인터임을 명시.)

    예 1)

   
void foo();
   
void (*foo_ptr)();             // 로 정의/선언 후
    foo_ptr = &foo;                
// 로 함수의 주소를 대입 cf) void (*foo_ptr)() = &foo;
    (*foo_ptr)();                  
// 로 사용 cf) foo_ptr(); 도 가능

   
const char* bar(int num);
   
const char* (*bar_ptr)(int);   // 혹은 const char* (*bar_ptr)(int num);로 정의/선언
    bar_ptr = &bar;                
// 호출하려는 함수의 주소를 넣고
    (*bar_ptr)(5);                
// 로 사용 cf) bar_ptr(5); 도 가능

    예 2)

   
class MyClass {
   
public:
       
void Func1(const string& txt);
       
static void Func2(const string& txt);
    };

   
void (MyClass::*Func1Ptr)(const string&) = &MyClass::Func1;
   
void (*Func2Ptr)(const string&) = &MyClass::Func2;        

    MyClass mc;
    (mc->*Func1Ptr)(
"abc");
    (*Func2Ptr)(
"abc");            // 형태로 사용 cf) Func2Ptr("abc"); 도 가능

    예 3)

    만일 MyClass::Func1, MyClass::Func2에 대한 함수 포인터를 MyClass의 멤버 변수로 하려면

   
class MyClass {
   
public:
       
void Func1(const string& txt);
       
static void Func2(const string& txt);
       
void (MyClass::*Func1Ptr)(const string&); // 내부라도 MyClass 스코프임을 밝혀야 함.
       
void (*Func2Ptr)(const string&);
    };

    MyClass mc;
    mc.Func1Ptr = &MyClass::Func1;
// 클래스내에서 setter를 사용하면 그냥 &Func1
    mc.Func2Ptr = &MyClass::Func2;
// 편의상 public으로 지정해서 대입했음.

    (mc.*(mc.Func1Ptr))(
"abc");    // 또는 (mc.*mc.Func1)("abc");
    (*mc.Func2Ptr)(
"abc");         // 전역 함수 포인터와 유사하므로 mc.Func2Ptr("abc") 가능.

    cf) 다른 멤버 함수에서 멤버 함수 포인터를 사용할 때는
    (
this->*Func1Ptr)("abc");
    Func2Ptr(
"abc");               // (*Func2Ptr)("abc")

    물론 꼭 MyClass의 멤버 변수로 존재할 필요는 없다. 다른 클래스의 멤버 변수로도 가능하다.

    주의 : 위의 경우는 꼭 필요한 상황인지, 설계상의 문제는 없는지 다시 한 번 고려할 것.
           다른 방법으로도 충분히 해결되는 문제임.


나.
typedef의 사용법 & 함수 포인터 배열

    함수 포인터의 배열은 무척 간단하다. 위의 예제의 foo 함수의 경우에는

   
void (*foo_ptr[])() = {foo1, foo2, foo3, ...};     // 선언&정의 + 대입
    (*foo_ptr[i])();                                  
// 사용

    로 하면 된다. 다른 함수 포인터도 유사하다.

    위에서 밝힌대로 함수 포인터는 변수이다. 변수는 형을 가진다. 그러면 함수 포인터의 형은 무엇인가?
    호출하려는 함수의 원형이 그 함수 포인터의 형이다. 즉 
typedef를 사용할 수 있다는 말이 된다.
    foo 함수에 대한 함수 포인터의 경우를 예로 들면

   
typedef void (*foo_ptr)();

    형태로 사용한다. 다만
void (*foo_ptr)();는 foo_ptr이 함수 포인터의 이름인데 반해
   
typedef void (*foo_ptr)(); 에서 foo_ptr은 함수 포인터의 형, void (*)()을 뜻하게 된다.
   
int a처럼 선언하듯이 typedef를 쓰면 foo_ptr fp; 뿐만 아니라 배열 선언을 foo_ptr fp[5];
    처럼 쓸 수 있고, 한결 깔끔하고 편리해지게 된다.
    개인적으로 함수 포인터와
typedef는 꼭 같이 쓰기를 권유한다.

    예 1)

   
class MyClass {
   
public:
       
void Func1(const string& txt);
       
static void Func2(const string& txt);
    };

   
typedef void (MyClass::*Func1Ptr)(const string&);
   
typedef void (*Func2Ptr)(const string&);

    Func1Ptr fptr = &MyClass::Func1;      
// 한결 더 의미가 명확해지고 코드 중복을 피할 수 있다.
    Func2Ptr ftpr2 = &MyClass::Func2;

    MyClass mc;
    (mc.*fptr)(
"abc");
    (*fptr2)(
"abc");

    예 2)

   
class MyClass {
       
typedef void (MyClass::*Func1Ptr)(const string&);
       
typedef void (*Func2Ptr)(const string&);
   
public:
       
void Func1(const string& txt);
       
static void Func2(const string& txt);
        MyClass() : fptr(Func1), fptr2(Func2) { }
       
void Invoke(const string& txt)
        {
            (
this->*fptr)(txt);
            (*fptr2)(txt);
        }
   
private:
        Func1Ptr fptr;
        Func2Ptr fptr2;
    };

    MyClass mc;
    mc.Invoke(
"abc");


참고 사이트
http://www.newty.de/fpt/fpt.html#defi

댓글

파트너스 활동을 통해 일정액의 수수료를 제공받을 수 있음



Total
Today
Yesterday
최근에 달린 댓글