728x90

선언방법

int (*pfunc1)(int, int);   // 일반적인 방법         
typedef int (*pfunc2)(int, int); // 편의를 위해 typdef를 이용하여 별칭을 정의
using pfunc3 = int(*)(int, int); // 편의를 위해 using을 이용하여 별칭을 정의

 

정의

함수 이름은 배열이름과 같ㅌ이 함수의 위치를 가리키는 주소값을 나타낸다. (실제론 &를 사용해서 함수를 참고해야 하는 경우도 있으니 절대적이진 않다.)

따라서 함수포인터 변수를 통해 동일한 시그니처의 함수를 전달할 수 있다.

 

사용법

- 1. 함수 포인터 변수 = [함수이름]

- 2. 함수 포인터 변수 = &[함수이름]

- 1. 함수이름();

- 2. (*함수이름)();

#include <iostream>

int func(int a, int b)
{
    return a + b;
}

int main()
{
    int (*pfunc)(int, int);

    pfunc = func; // 방식1.배열이름과 같이 함수이름이 주소값을 나타낸다. 하지만 이는 C언어와의 호환성 때문에 컴파일러에서 지원 하는 기능이다.
    pfunc = &func; // 방식2. 위 방식보다 이게 FM 방식이다. 클래스 멤버함수를 변수에 전달할 때는 FM 방식을 따라야 하는 경우가 있다.
    
    pfunc(1,2); // 방식1.편의
    (*pfunc)(1, 2); // 방식2.FM
}

 

함수 포인터 변수가 아닌 일반 함수 변수는 사용하지 않을까?

- 함수 변수는 단순히 함수 선언부이다. 따라서 linking 과정에서 같은 시그니처(이름 포함) 정의부현을 찾아서 해당 함수가 호출된다.

- 변수에 다른 함수를 넘길 수 없다.

#include <iostream>
using namespace std;

int func(int a, int b)
{
    cout << "func()" << endl;
    return a + b;
}

int func1(int a, int b)
{
    cout << "func1()" << endl;
    return a + b;
}


int main()
{
    int (func)(int, int); // 일단적인 타입과 다르게 메모리에 적재 되지도 않음. 단순히 함수 선언부이다.

    {
        func = func1; // (x)
    }

    {
        func(); // func 함수 정의가 있다면 호출. 없다면 링킹에러.
    }
 }

따라서 아래와 같은 방식으로 사용된다.

#include <iostream>
using namespace std;

int func(int a, int b)
{
    return a + b;
}

int main()
{       
    // 선호 되는 방식
    {
        typedef int (*pfunc1)(int, int); 
        using pfunc2 = int(*)(int, int); 

        pfunc1 p1 = func;
        pfunc2 p2 = func;
    }

    // 비선호 되는 방식
    {
        typedef int (pfunc1)(int, int);
        using pfunc2 = int(int, int);

        pfunc1* p1 = func;
        pfunc2* p2 = func;
    }
 }

 

예외적인 사용법 - 멤버함수를 보관하는 함수

위와 같은 방식으로(전역, 정적 함수만 가능) 특정 클래스의 비정적 멤버함수를 변수에 받을 수 없다.

비정적 멤버함수를 변수로 받을 때는 전달방식, 호출방식 모두 차이가 있으니, 아래 코드를 통해 확인 하자.

#include <iostream>
using namespace std;

class Knight
{
public:
    int func(int a, int b)
    {
        cout << "Knight:func()" << endl;
        return a + b;
    }
};

int main()
{       
    int (Knight::*pmfunc)(int, int);

    {
        pmfunc = Knight::func; // 일반적인 방식으로 전달 불가.(컴파일 에러)
        pmfunc = &Knight::func; // FM으로 &연산자 사용 해야 함.
    }

    {
        Knight k1;

        k1.pmfunc(1, 2); // 불가
        (k1.*pmfunc)(1, 2); // 가능(FM)
    }

    {
        Knight* k1 = new Knight();
        (k1->pmfunc)(1, 2); // 불가
        (k1->*pmfunc)(1, 2); // 가능(FM)
    }
    
 }

 


공부한 내용을 개인적으로 복습하기 쉬운 형태로 정리했습니다.

잘못된 내용이 있는 경우 언제든 댓글 혹은 이메일로 지적해주시면 감사드립니다.

728x90

'Programming Language > C++' 카테고리의 다른 글

auto  (0) 2022.02.06
함수 객체(함수자, Functor)  (0) 2022.02.06
2-2_입력( <<,manipulator,조정자)  (0) 2021.12.07
C++/StackPadding  (0) 2021.11.23
c/c++/size_t,intptr_t,uintptr_t  (0) 2021.11.23

+ Recent posts