[C++] 함수 포인터.

빵욱·2024년 8월 18일

함수포인터에 대해 정리..

함수 포인터?

함수 포인터(Function Pointer)는 C++에서 함수를 가리키는 포인터.
즉, 함수의 메모리 주소를 저장하여 그 주소를 통해 함수를 호출할 수 있는 기능.
(함수는 특정 메모리 주소에서 시작한다.)



함수 포인터 문법

함수포인터 문법.
return_type (*pointer_name)(parameter_types);

예제를 위해 아래과 같은 코드들이 선언되었다.

int foo()
{
    return 10;
}

bool GetLagerNumber(int a, int b)
{
    return a > b;
}

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

class TestClass {
public:
    void printMessage() {
        std::cout << "Hello from TestClass" << std::endl;
    }

    static void staticFunction() {
        std::cout << "Static function" << std::endl;
    }
};

class Counter {
public:
    int value = 0;

    void increment() {
        value++;
    }

    void printValue() const {
        std::cout << "Value: " << value << std::endl;
    }
};



예제

// fcnPtr은 인수가 없고 정수를 반환하는 함수에 대한 포인터다.
// (즉, 함수 포인터) 그러므로 이 타입과 같은 함수를 가리킬 수 있다. 
int (*fcnPtr)(); // 비 상수 포인터.
fcnPtr = foo;
int (* const fcnPtr2)() = foo; // 상수 포인터, 선언과 동시에 초기화.
std::cout << fcnPtr() << std::endl;



별칭사용

// 별칭
// compareFunc이라는 별칭을 사용했기 때문에 변수 이름은 지정할 필요X
using CompareFunc = bool (*)(int, int);
CompareFunc compare1 = GetLagerNumber;
std::cout << ((compare1(3, 2) == true) ? "true" : "false") << std::endl;

using를 사용한 별칭은 c++11부터 가능하다고 한다.


std::function

std::function을 통해 더 쉽게 함수 포인터를 사용할 수 있다.

 // std:function  (c++ 11)
 // std:function<반환형(매개변수..)>
 // #include <functional>
 std::function<int(int, int)> addFunc = Add;
 std::cout << "\n\n\n" << std::endl;
 std::cout << addFunc(5,5) << std::endl;

std::funtion 이란 ?

std::function은 C++ 표준 라이브러리에서 제공하는 범용 함수 래퍼(Wrapper) 클래스입니다. 함수 포인터뿐만 아니라, 람다 표현식, 멤버 함수 포인터, 일반 함수 등 다양한 호출 가능한 객체들을 캡슐화할 수 있습니다. std::function은 동적 함수 호출을 간단하게 처리하며, 함수 포인터보다 훨씬 유연하게 작동합니다.

라고 한다.


일반 함수 포인터와 멤버 함수 포인터.

  • 일반 함수 포인터는 단순히 함수의 주소를 저장.
  • 멤버 함수 포인터는 특정 클래스의 멤버 함수만을 가리킬 수 있도록 선언.
    멤버 함수 포인터 선언 방법
    return_type (ClassName::*pointer_name)(parameter_types);

호출 방식 차이

함수 호출 방식의 차이
일반 함수 포인터는 함수의 주소를 저장하고, 그 주소를 통해 함수를 호출.
멤버 함수 포인터는 특정 객체를 통해 멤버 함수에 접근해야 하며,
이를 위해 객체의 참조나 포인터가 필요.
멤버 함수는 객체의 상태(멤버 변수)에 접근할 수 있으므로 객체가 반드시 필요하다.

 // 일반 함수 포인터
 int (*func_ptr)(int, int) = Add;
// 멤버 함수 포인터
TestClass tc;

void (TestClass::*member_func_ptr)() = &TestClass::printMessage;

// 멤버 함수 포인터 호출 시, 객체 참조를 통해 호출해야 함
(tc.*member_func_ptr)();  // 출력: Hello from MyClass

Counter counter;

// 멤버 함수 포인터 선언
void (Counter:: * inc_ptr)() = &Counter::increment;
void (Counter:: * print_ptr)() const = &Counter::printValue;

// 객체를 통해 멤버 함수 호출
(counter.*inc_ptr)();
(counter.*print_ptr)();

함수 상태 의존성

함수의 상태 의존성

  • 일반 함수는 상태가 없는 독립적인 함수. 함수가 외부 상태에 의존하지 않으며, 호출될 때마다 동일한 결과를 반환한다.(매개변수가 같을 경우).
  • 멤버 함수는 클래스의 멤버 변수를 통해 클래스의 상태에 의존한다. 따라서 객체의 상태에 따라 호출 결과가 달라질 수 있습니다.

정적 멤버 함수 vs 비정적 멤버 함수

정적 멤버 함수는 일반 함수처럼 객체 없이도 호출할 수 있으며, 일반 함수 포인터로도 가리킬 수 있다.
비정적 멤버 함수는 객체와 연관된 상태를 가지고 있으므로 반드시 객체를 통해 호출해야 한다.

// 정적 멤버 함수는 일반 함수처럼 호출 가능
void (*static_func_ptr)() = &TestClass::staticFunction;
static_func_ptr();  // 출력: Static function

멤버 함수 포인터는 객체 인스턴스 내부에 생성된 것인가 ?
=> 아니다.
main 함수 내에서 선언된 지역 변수다. ( 위 예제들은 콘솔 프로젝트에서 main 함수내에서 작성함.)
이 변수들은 Counter 클래스의 멤버 함수 포인터로, counter 객체의 멤버 함수에 접근하기 위해 사용된다.

std::function에 멤버 함수 포인터 할당.

TestClass tcObj;
// 멤버 함수 바인딩은 아래과 같이 사용한다고 한다.
auto func = std::bind(&TestClass::printMessage, &tcObj, std::placeholders::_1);

std::bind 란 ?

std::bind는 C++11에서 도입된 함수로, 함수 객체나 멤버 함수를 호출할 때, 미리 일부 인자를 바인딩하여 나중에 호출할 수 있도록 준비하는 기능을 제공합니다. 즉, std::bind는 호출할 함수에 일부 인자를 고정해두고 나중에 필요한 다른 인자를 넣어 호출할 수 있게 해줍니다.

라고한다.
정확히 이해가 되지 않아서 나중에 공부해서 자세하게 정리해보록 하겠다.

std::bind는 std::bind(callable, args...)처럼 사용한다.

// 일반함수 바인딩도 가능한데 인자 고정 같은 것이 가능. std::bind로 첫 번째 인자 고정 (a = 10)
auto add_with_10 = std::bind(Add, 10, std::placeholders::_1);

std::cout << "10 + 5 = " << add_with_10(5) << std::endl;

// std::placeholders
// std::placeholders::_1, _2 등의 플레이스홀더는 아직 바인딩되지 않은 인자들을 나타낸다.
// 위 예제에서 std::placeholders::_1은 나중에 전달될 첫 번째 인자를 나타낸다.
profile
rove drink eat

0개의 댓글