본문 바로가기
프로그래밍/C++

C++ 함수 포인터 (Function Pointer)

by 머니테크리더 2023. 9. 29.
반응형

C++ 함수 포인터 (Function Pointer)
C++ 함수 포인터 (Function Pointer)

 

🔖 INDEX

     

     

    함수 포인터의 이해

    C++에서 함수는 메모리에 저장되어 있으며, 따라서 그 함수의 시작 주소를 가리키는 포인터를 사용할 수 있습니다. 이러한 포인터를 함수 포인터라고 합니다.

     

    함수 포인터의 선언

    함수 포인터를 선언하는 것은 처음에는 조금 복잡해 보일 수 있습니다. 그러나 몇 번 연습하면 쉽게 이해하게 됩니다. 다음은 int 타입을 반환하고, 두 개의 int 인자를 받는 함수 포인터의 선언 예시입니다.

    int (*FunctionPtr)(int, int);

    이때 FunctionPtr는 함수 포인터의 이름입니다.

     

    함수 포인터 초기화

    함수 이름은 그 함수의 시작 주소를 의미합니다. 따라서 함수 포인터를 해당 함수의 주소로 초기화할 수 있습니다.

    int add(int x, int y) {
        return x + y;
    }
    
    int (*FunctionPtr)(int, int) = add;

     

    함수 포인터를 이용한 함수 호출

    함수 포인터를 통해서 함수를 호출할 수 있습니다.

    int result = FunctionPtr(5, 3);  // add 함수를 호출하고 결과는 8입니다.

     

    함수 포인터 배열

    여러 함수들을 가리키는 함수 포인터들의 배열도 만들 수 있습니다. 이는 예를 들어 다양한 연산들을 동적으로 선택하여 수행할 때 유용하게 사용됩니다.

    int multiply(int x, int y) {
        return x * y;
    }
    
    int (*operations[])(int, int) = {add, subtract, multiply};

     

    함수 포인터와 콜백

    함수 포인터는 콜백 함수를 구현하는 데에 주로 사용됩니다. 콜백은 어떤 함수가 다른 함수를 인자로 받아, 특정 동작이 끝나고 나서 해당 함수를 호출하는 패턴을 말합니다.

    void executeOperation(int x, int y, int (*operationFunc)(int, int)) {
        int result = operationFunc(x, y);
        cout << "Result: " << result << endl;
    }
    
    executeOperation(5, 3, add);  // "Result: 8" 출력

    위 예제에서 executeOperation 함수는 연산 함수를 인자로 받아 그 연산의 결과를 출력하는 함수입니다. 여기서 add 함수는 콜백 함수의 역할을 합니다.

     

     

    함수 포인터의 사용 이유 및 주의점

     

    왜 함수 포인터를 사용할까?

    • 동적 함수 호출: 프로그램 실행 중에 어떤 함수를 호출할지 결정할 수 있습니다.
    • 콜백 함수: 특정 함수가 완료된 후에 호출될 함수를 전달하는 방식으로 사용됩니다. 예를 들어, 정렬 함수에서 사용자가 원하는 비교 방식을 정의하는 함수를 콜백으로 제공할 수 있습니다.
    • 함수 배열: 여러 함수들을 배열로 관리하면서, 필요에 따라 선택하여 호출할 수 있습니다.

     

    함수 포인터의 주의점

    • 타입 일치: 함수 포인터는 해당 함수의 시그니처와 정확히 일치해야 합니다. 반환 타입, 매개변수의 타입 및 순서 모두 일치해야 합니다.
    • 올바른 주소: 함수 포인터가 가리키는 주소가 올바른 함수의 주소인지 항상 확인해야 합니다. 잘못된 주소를 호출하면 프로그램이 예기치 않게 종료될 수 있습니다.

     

    함수 포인터 가독성 높이는 방법

    함수 포인터의 선언 문법이 복잡해 보일 수 있기 때문에, 이를 더 간결하고 명확하게 만들기 위해 여러 방법이 사용될 수 있습니다. 주로 typedef나 C++11부터 제공하는 using을 활용하여 이를 달성합니다.

     

    typedef 사용하기

    typedef를 사용하면 함수 포인터의 타입에 별칭(alias)을 줄 수 있습니다. 이로써 함수 포인터 선언이 훨씬 간결해집니다.

    예를 들어, 아래와 같은 함수가 있다고 가정합시다.

    void displayMessage(int times);

     

    이 함수에 대한 포인터를 typedef를 사용하여 다음과 같이 선언할 수 있습니다.

    typedef void (*DisplayFunc)(int);

     

    이제 DisplayFunc라는 이름으로 함수 포인터를 선언할 수 있습니다.

    DisplayFunc myFunc = displayMessage;

     

    using 사용하기 (C++11 이후)

    C++11부터는 typedef와 유사한 기능을 하는 using을 사용하여 타입 별칭을 지정할 수 있습니다. 이는 typedef보다 더 간결하고 읽기 쉬운 문법을 제공합니다.

    using DisplayFunc = void (*)(int);

     

    이렇게 선언한 후에도 DisplayFunc를 사용하여 함수 포인터를 선언하고 초기화할 수 있습니다.

    DisplayFunc myFunc = displayMessage;

     

    typedef나 using을 사용하여 함수 포인터의 복잡한 선언을 간결하게 만들면 코드의 가독성이 크게 향상됩니다. 특히 프로젝트에서 여러 번 같은 타입의 함수 포인터를 사용할 때 이러한 방식은 코드를 더욱 깔끔하게 유지하는 데 도움이 됩니다.

     

     

    C++11에서의 std::function

    C++11에서는 함수 포인터의 사용을 대체하거나 보완하기 위해 std::function이 도입되었습니다. std::function은 함수, 람다, 함수 객체, 멤버 함수 등 다양한 호출 가능 객체(callable object)를 일관된 방식으로 저장하고 호출하는데 사용됩니다.

     

    기본 사용법

    std::function의 기본 선언 형태는 다음과 같습니다:

    std::function<반환형(매개변수 타입들)>

     

    예를 들어, 아래와 같은 함수가 있다고 가정합시다.

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

     

    위 함수를 std::function으로 저장하려면 다음과 같이 합니다:

    std::function<int(int, int)> func = add;

     

    람다와 함께 사용하기

    std::function은 람다 표현식과 함께 사용될 때 매우 유용합니다.

    std::function<int(int, int)> func = [](int a, int b) {
        return a + b;
    };

     

    함수 객체와 함께 사용하기

    클래스나 구조체에 operator()가 정의된 객체를 함수 객체(functor)라고 합니다. 이러한 함수 객체도 std::function에 저장될 수 있습니다.

    struct Multiplier {
        int operator()(int a, int b) {
            return a * b;
        }
    };
    
    std::function<int(int, int)> func = Multiplier();

     

    멤버 함수와 함께 사용하기

    클래스의 멤버 함수도 std::function으로 저장할 수 있지만, std::bind나 람다와 같은 도구와 함께 사용되어야 합니다.

    class Calculator {
    public:
        int subtract(int a, int b) {
            return a - b;
        }
    };
    
    Calculator calc;
    std::function<int(int, int)> func = std::bind(&Calculator::subtract, &calc, std::placeholders::_1, std::placeholders::_2);

     

    std::function은 C++11에서 도입된 강력한 기능으로, 다양한 호출 가능 객체를 일관된 방식으로 다룰 수 있게 해줍니다. 기존의 함수 포인터나 함수 객체만을 사용하는 방식보다 훨씬 유연하고 간결한 코드 작성이 가능하게 됩니다.

     

     

    댓글