다시 호출하다? 역으로 호출하다.
게임을 만들 때 이런 콜백 개념이 자주 등장함.
MoveTask실습등
어떤 상황이 일어나면 -> 이 기능을 호출해줘
UI스킬 버튼을 누르면 -> 스킬을 쓰는 함수를 호출해줘.
함수 포인터 + 함수 객체 + 템플릿
이런식으로 Item클래스가 있고
이상태에서 어떤 조건을 체크를 하기 위해서
(TODO에 들어갈조건 체크)
FindItem이라는 함수로 item을 찾는다고 가정을 하자.
함수포인터를 마지막 인자에 넘겨주어서
동작을 넣어 줄 수 있었다.
가장 간단한 방식으로 콜백을 넣어 줄 수 있다는 '강점'은 있지만
'어떤 상태를 저장할 수 없다.' 라는 단점이 존재한다.
그래서 등장한게 '함수 객체'이다.
함수 객체를 사용을 하면 '생성시점'과 '실행시점'을 구분할 수 있다는 장점이 생김.
간단한게 특정조건 하나를 체크를 하는 경우가 아니라면
이렇게 함수 포인터를 마지막 인자에 넣어서 동작을 넣어주면 불리하다.
_ownerId 라는 멤버변수도 함께 전달해주고 싶은 경우에.
그래서 일단 Functor를 만들어 줄 것이다.
이렇게 '상태'를 저장하기 위해서 _ownerId를 들고있도록 하자.
그리고 이 Functor도 '함수 처럼' 동작을 해야하니까
operator 를 '오버로딩' 해주도록 하자.
비교만 할꺼고 수정은 안할꺼라서 const Item* item을 받도록 하자.
이렇게 해주도록 하자.
마찬가지로 Rarity를 찾아주는 Functor도 같은 방식으로
'상태'를 가지고있고 operator ()를 통해 똑같이 구현을 해주면 될 것이다.
이렇게. (_rarity가 2 이상이면 레어 아이템으로 간주함)
이런식으로 늘릴 수가 있고
'함수 포인터'와는 다르게
객체가 독립적이다 보니까
이런식으로 데이터(상태)를 늘려줄 수 있을 것이다.
즉, 각기 다른 상태값을 가질 수 있다는 것이다.
그래서 이제 여기에 함수 포인터를 넘겨주는 것이 아니라
Functor라는 것 자체를 넘겨주면 될 것이다.
그런데 매개변수로 넘겨줄려면 '타입'이 있어야하기 때문에
이런식으로 까지는 아름답게 된다.
근데 이렇게 명시적으로 넣어 주었기 때문에
FinByRarity를 넘겨주고싶으면 다시 '명시적'으로 적어주어야한다.
(상속을 사용해서도 해결이 가능하지만 -> 복잡하다)
곰곰히 생각하면 마지막 인자로 받아주는 Functor는
결국 46번째 줄처럼 동작을 한다는 점이 공통적이다. (함수처럼 동작할 것이라는 점)
그래서 이전시간에 배운 템플릿을 사용해서
T라는 타입의 selector를 이제는 사용을 할 수 있을 것이다.
그러면이게 이제 FindByOwnerId일 수도있고 FindByRarity일 수도 있다.
그래서 이제 main에서
이렇게 functor를 만들어 주면
이제 FindItem 함수를 호출할 수 있다.
이렇게 넣어주고 이제 중요한데
이제 '콜백함수'를 넣어주는 개념이 될 것이다.
여기서 이제 functor1을 함수객체를 넣어주는 것이다.
(C++11의 람다 사용하면 functor를 만들지 않고 좀더 편하게 만들 수 있기는 하다)
그래서 이렇게 하면 강제로 넣어준 아이템 찾을 수 있다.
functor의 '생성'은 55, 59에서 하고
실행하는 부분은 FindItem을 호출하고 안에서 '실행 시점'이 잡히는 것이다.
functor1의 '상태'는 _ownerId가 10인 상태를 들고있고
여기서 이제 연산자 오버로딩을 해서 함수처럼 사용할 수 있도록 만들어 주었기 때문에
46번째줄이 '실행 시점'이다.
그래서 함수 포인터 + 함수 객체 + 템플릿을 잘 활용해야하고
STL을 공부하기 위한 기초가 됨.