본문 바로가기
Script/C++

[C++] Chapter 10. 콜백 함수 (Callback)

by song.ift 2023. 5. 15.

콜백함수

함수 포인터 + 함수 객체 + 템플릿

콜백 (Callback) : 다시 호출하다? 역으로 호출하다?

 

게임을 만들 때, 이런 콜백의 개념이 자주 등장한다.

ex) MoveTask 실습 등

 

어떤 상황이 일어나면 → 이 기능을 호출해줘

ex) UI 스킬 버튼을 누르면 → 스킬을 쓰는 함수를 호출 (함수 포인터 or 함수 객체 등 으로 넘겨줌)

 

함수 포인터는 사용 안했고, 함수 객체와 템플릿을 사용한 예

class Item
{
    public:
        int _itemId = 0;
        int _rarity = 0;
        int _ownerId = 0;
}

class FindByOwnerId
{
    public:
        // 함수 객체를 사용하기 위한 연산자 오버로딩
        bool operator()(const Item* item)
        {
            return (item->_ownerId == _ownerId);
        }	

    public:
        int _ownerId;
}

class FindByRarity
{
    public:
        // 함수 객체를 사용하기 위한 연산자 오버로딩
        bool operator()(const Item* item)
        {
            return (item->_rarity == _rarity );
        }	

    public:
        int _rarity;
}

// 함수 포인터, 함수 객체 대신 템플릿으로 유연하게 사용
template<typename T>
Item* FindItem(Item items[], int ItemCount, T selector)
{
    for(int i = 0; i < ItemCount; ++i)
    {
        Item* item = &items[i]

        // TODO : 조건체크
        if (selector(item))    // 함수 객체
            return item;
    }
    return nullptr;
}

int main()
{
    Item items[10];
    items[3]._ownerId = 100;
    items[8]._rarity= 1;

    FindByOwnerId functor1;
    functor1._ownerId = 100;

    FindByRarity functor2;
    functor2._rarity= 1;

    Item* item1 =	FindItem(items, 10, functor1);
    Item* item2 =	FindItem(items, 10, functor2);
}

Item* FindItem(Item items[], int ItemCount, bool(*func)(const Item*))

함수 포인터인 경우는 상태(멤버)를 가질 수 없기 때문에 데이터를 제어할 수가 없고, 시그니처가 통일돼야 한다.

 

Item* FindItem(Item items[], int ItemCount, FindByOwnerId selector)

Item* FindItem(Item items[], int ItemCount, FindByRarity selector)

함수 객체인자가 명시적으로 들어갔기 때문에, 다른 클래스를 사용하고 싶으면 수정해야 한다.

물론 공통적인 부모클래스로 상속을 받아 캐스팅을 통해 가능할 수 있긴 한데, 그러면 조금 복잡하다.

 

메인 코드처럼 템플릿 형식으로 만들면 어떤 타입이든 범용적으로 작용할 수 있다.

결국에 콜백을 구현할 때, 함수 포인터함수 객체 템플릿이든 기초 문법과 장단점을 알고 있으면 다양하게 선택해서 응용할 수 있다.

나중에 람다식을 이용하면 함수를 만들지 않고, 더 편하게 만들 수 있다.

댓글