함수포인터에 대해 정리..
함수 포인터(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 (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은 동적 함수 호출을 간단하게 처리하며, 함수 포인터보다 훨씬 유연하게 작동합니다.
라고 한다.
함수 호출 방식의 차이
일반 함수 포인터는 함수의 주소를 저장하고, 그 주소를 통해 함수를 호출.
멤버 함수 포인터는 특정 객체를 통해 멤버 함수에 접근해야 하며,
이를 위해 객체의 참조나 포인터가 필요.
멤버 함수는 객체의 상태(멤버 변수)에 접근할 수 있으므로 객체가 반드시 필요하다.
// 일반 함수 포인터
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)();
함수의 상태 의존성
정적 멤버 함수는 일반 함수처럼 객체 없이도 호출할 수 있으며, 일반 함수 포인터로도 가리킬 수 있다.
비정적 멤버 함수는 객체와 연관된 상태를 가지고 있으므로 반드시 객체를 통해 호출해야 한다.
// 정적 멤버 함수는 일반 함수처럼 호출 가능
void (*static_func_ptr)() = &TestClass::staticFunction;
static_func_ptr(); // 출력: Static function
멤버 함수 포인터는 객체 인스턴스 내부에 생성된 것인가 ?
=> 아니다.
main 함수 내에서 선언된 지역 변수다. ( 위 예제들은 콘솔 프로젝트에서 main 함수내에서 작성함.)
이 변수들은 Counter 클래스의 멤버 함수 포인터로, counter 객체의 멤버 함수에 접근하기 위해 사용된다.
TestClass tcObj;
// 멤버 함수 바인딩은 아래과 같이 사용한다고 한다.
auto func = std::bind(&TestClass::printMessage, &tcObj, std::placeholders::_1);
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은 나중에 전달될 첫 번째 인자를 나타낸다.