함수 포인터, 펑터, 콜백 함수

Oak_Cassia·2021년 11월 27일
0

함수 포인터

관리와 확장에 편리하다.
함수를 매개변수로 전달할 수 있다.(동작 전달)

int (*f2)(int, int);
typedef int(FUNC_TYPE)(int, int);
FUNC_TYPE *f1;
typedef int (*FUNC3)(int, int);
	FUNC3 f3 = &Mul; // &생략할 수있다.

int를 반환하고 int 변수 두개를 매개변수로 받는 함수에 대한 포인터

멤버 함수 포인터

멤버 함수에 대한 포인터의 형식에 몇 가지 다른 점이 있다.

  • 멤버 함수를 실행할 객체가 필요하다.(static 멤버함수라면 ?)
  • 값을 할당할 때 &를 생략할 수 없다.
  • 호출할 때 .*연산자와 ->* 연산자를 사용한다.
typedef void(Num2::*PMFUNC)(FUNC);
	PMFUNC pmf = &Num2::Show; //멤버함수 포인터는 &를 생략할 수 없다!!
	PMFUNC pmf2 = &Num2::Oper;
	(*num.*pmf)(f1); // 괄호를 꼭 해주어야한다.  .* 연산자와 ->* 연산자
	(num->*pmf2)(Mul); // 괄호를 꼭 해주어야한다. 멤버변수로 pmf2가 있는지 헷갈리기 때문이다.(컴파일러가)

함수 객체(펑터)

함수 포인터는 동일한 시그니처의 함수만 가리킬 수 있지만 펑터는 ()연산자 오버로딩을 통해 다양한 함수 구현이 가능하다.

class ObFunc // 함수 객체(펑터) ()연산자 오버로딩을 통해 다양한 시그니처를 함수 포인터로 이용이 가능하다.
{
public:
	int val;
	float val2;

	void operator()()
	{
		cout << "------펑터-------"<<endl;
	}

	int operator()(int a)
	{
		cout << "val: " << val << endl;
		return a;
	}
	float operator()(float a)
	{
		cout << "val2: " << val2 << endl;
		return a;
	}
};

콜백 함수

  • 인자로 전달되는 함수
  • 어떤 이벤트로 인해 호출되는 함수
#include <iostream>
using namespace std;

typedef int(*FUNC)(int, int);

int Add(int a, int b)
{
	cout << "더한다" << endl;
	return a + b;
}

int Sub(int a, int b)
{
	cout << "뺸다" << endl;
	return a - b;
}

int Mul(int a, int b)
{
	cout << "곱한다" << endl;
	return a * b;
}

class Num2
{
public:
	int num1;
	int num2;

	void Oper(FUNC f1)
	{
		cout<<f1(num1, num2)<<endl;
	}
	void Show(FUNC f2)
	{
		cout << "num1 : " << num1 << " , num2 :" << num2 << endl;
		cout << "위 숫자들을 ";
		f2(num1, num2);
	}
};

class ObFunc // 함수 객체(펑터) ()연산자 오버로딩을 통해 다양한 시그니처를 함수 포인터로 이용이 가능하다.
{
public:
	int val;
	float val2;

	void operator()()
	{
		cout << "------펑터-------"<<endl;
	}

	int operator()(int a)
	{
		cout << "val: " << val << endl;
		return a;
	}
	float operator()(float a)
	{
		cout << "val2: " << val2 << endl;
		return a;
	}
};

int main()
{
	typedef int(FUNC_TYPE)(int, int);
	//using FUNC_TYPE=int(int, int) 모던 c++ 
	FUNC_TYPE *f1;
	f1 = Add;
	int a = f1(1, 3);
	cout <<"a: 1+3 = " << a << endl;

	//타입정의 없이 바로
	int (*f2)(int, int);
	f2 = &Sub; //&붙이나 안붙이나 같다!!!
	int b = f2(4, 2);
	cout<< "b: 4-2 = " << b<< endl;

	typedef int (*FUNC3)(int, int);
	FUNC3 f3 = &Mul;
	int	c = f3(a, b);
	cout << "c: a*b = " << c << endl;

	int (*f4)(int, int);
	f4 = Sub;
	int d = (*f4)(c, b); // (*f4) 와 같이 호출하는 형식도 f2로 호출하는 것과 동일하다
	cout << "d: c-b = " << d << endl;

	cout <<"------여기부터 함수 포인터를 멤버함수의 매개변수로 하고 인자로 전달한 것-------" << endl;
	Num2* num= new Num2;
	num->num1 = 10;
	num->num2 = 20;
	num->Oper(Add);
	num->Oper(Sub);
	num->Oper(Mul);
	//위의 것들은 정적, 전역함수만 가능하다.
	//멤버함수는 어떻게 할까? 객체가 있어야 하기 때문에 다르다!ㅋ
	typedef void(Num2::*PMFUNC)(FUNC);
	PMFUNC pmf = &Num2::Show; //멤버함수 포인터는 &를 생략할 수 없다!!
	PMFUNC pmf2 = &Num2::Oper;
	(*num.*pmf)(f1); // 괄호를 꼭 해주어야한다.  .* 연산자와 ->* 연산자
	(num->*pmf2)(Mul); // 괄호를 꼭 해주어야한다. 멤버변수로 pmf2가 있는지 헷갈리기 때문이다.(컴파일러가)
	
	ObFunc *obf= new ObFunc;
	(*obf)();
	obf->val = 10;
	obf->val2 = 11.99f;
	int ao = 4;
	float bo=5.55f;
	(*obf)(ao);
	obf->operator()(bo);

	ObFunc obf1;
	obf1();
    ObFunc();
}

profile
rust로 뭐할까

0개의 댓글