함수 객체
함수 객체(Functor), 함수처럼 동작하는 객체
함수 포인터의 단점이 있었다. 그 시그니처와 동일하지 않은 함수는 사용할 수 없다는 점이다.
또, 상태를 가질 수 없다는 점이 단점이다.
클래스에는 데이터와 함수를 동시에 가질 수 있다. hp가 100 이라면 100이라는 상태를 가지고 있는 것이다.
함수처럼 동작 하는 객체가 함수 객체이다.
() 연산자 오버로딩이 필요하다.
#include <iostream>
using namespace std;
class Func
{
public:
void operator()()
{
cout << "Test" << endl;
}
void operator()(int num)
{
cout << "Test num" << endl;
}
public:
};
int main()
{
Func func;
func();
return 0;
}
이런식으로 연산자를 오버로딩을 해서 객체를 함수처럼 사용하는 것이다.
예시 들자면
MMO 에서 함수 객체를 자주 사용하는데 클라이언트와 서버랑 통신을 계속 할 것이다.
서버는 클라가 보내준 네트워크 패킷을 받아서 처리한다.(클라 : 나 (5,0) 좌표로 이동시켜줘)
다만 서버에 패킷을 너무 많이 들어오면 버벅이게 될텐데 순차적으로 처리할게 될 것이다. 이를 객체를 만들어 처리할 수 있다.
#include <iostream>
using namespace std;
class MoveTask
{
public:
void operator()()
{
// TODO
cout << "해당 좌표로 이동" << endl;
}
public:
int _playerId;
int _posX;
int _posY;
};
int main()
{
// 이동 요청
// 5 , 0 의 좌표로 플레이어 100번을 옮겨라!
// 라는 명령이 들어옴
MoveTask task;
task._playerId = 100;
task._posX = 5;
task._posY = 0;
// 나중에 순차적으로 처리하며 여유가 될 때 일감을 실행
task();
return 0;
}
이를 커맨드 패턴이라고 부르기도 한다.
템플릿 기초(함수 템플릿)
C++에서 템플릿은 가장 어려운 부분이라고 말할 수 있다.
템플릿은 무엇인가? 함수나 클래스를 찍어내는 툴이다.
함수 템플릿
만약 우리가 정수를 매개변수로 받아 로그를 출력하는 함수를 만들었다고 해보자. 만약 정수가 아닌 다른 값을 출력
한다고 해보자. 그렇게되면 그 값에 맞는 함수 오버로딩을 해야할 것이다. 그렇다면 함수가 무진장 많이 나타나게 될 것 이다.
이때 사용이 가능한게 템플릿이다.
#include <iostream>
using namespace std;
template<typename T>
void Print(T a)
{
cout << a << endl;
}
int main()
{
Print(2);
Print("asd");
return 0;
}
템플릿 함수가 되게 특별한게 아니라 그냥 컴파일러가 알아서 함수를 여러개 만들어 주는것이다.
또한 다른 방식으로도 사용 가능하다.
#include <iostream>
using namespace std;
template<typename T>
void Print(T a)
{
cout << a << endl;
}
template<typename T>
T Add(T a, T b)
{
return a + b;
}
// 2개 이상 있는 경우
template<typename T1, typename T2>
void Print(T1 a, T2 b)
{
cout << a << " " << b << endl;
}
int main()
{
float a = Add(1.2f, 1.3f);
Print("aasd", 123);
return 0;
}
템플릿 특수화
특정 템플릿을 강제화 할 수 있다. 예를 들어 템플릿 화 되어 있는 함수를 따로 필요한 경우 빼고 싶은 경우에 다음과 같이 작성해서 Knight만 처리할 수 있다.
template<>
void Print(Knight k)
{
cout << k._hp << endl;
}
template<typename T>
void Print(T a)
{
cout << a << endl;
}
이 경우에 우리가 Print를 호출할 때 매개변수로 Knight를 넣어주게되면 윗 버전이 출력하게된다.
템플릿 기초(클래스 템플릿)
함수 템플릿에서 나왔던 내용이 거의 다 적용된다.
#include <iostream>
using namespace std;
class RandomBox
{
public:
int GetRandom()
{
int random = rand() % 10;
return _data[random];
}
private:
int _data[10] = { 1,2,3,4,5,6,7,8,9,10 };
};
int main()
{
srand((unsigned int)(time(nullptr)));
RandomBox rb;
cout << rb.GetRandom();
return 0;
}
만약 이런 경우에 random한 값이 int가 아니라 다른 형식이라면 또 다른 클래스를 파야한다. 되게 불편하기 때문에 이걸 템플릿을 사용해서 처리할 수 있다.
#include <iostream>
using namespace std;
template<typename T>
class RandomBox
{
public:
T GetRandom()
{
int random = rand() % 10;
return _data[random];
}
private:
T _data[10] = { 1,2,3,4,5,6,7,8,9,10 };
};
int main()
{
srand((unsigned int)(time(nullptr)));
RandomBox<int> rb;
cout << rb.GetRandom();
return 0;
}
템플릿 특수화 역시 class에도 동시에 적용할 수 있다.
콜백 함수
Callback의 뜻에는 다시 호출하다, 역으로 호출하다 등이 있다.
게임을 만들 때 이런 콜백의 개념이 자주 등장한다.
어떤 상황이 일어나면 -> 이 기능을 호출해줘. 등이다.
ex ) UI 스킬 버튼을 누르면 -> 스킬을 쓰는 함수를 호출해줘!
우리가 이전 포스팅에서 Item을 찾는 것을 함수포인터를 사용해 작성해봤다. 그리고 그것의 한계는 명확했다. 상태를 저장할 수 없기 때문이다.
#include <iostream>
using namespace std;
class Item
{
public:
Item() : _itemId(0), _rarity(0), _ownerId(0)
{
}
public:
int _itemId;
int _rarity;
int _ownerId;
};
class FindByOwnerId
{
public:
bool operator()(const Item* item)
{
return (item->_ownerId == _onwerId);
}
public:
int _onwerId;
};
class FindByRarityId
{
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];
// 조건 체크
if(selector(item))
return item;
}
return nullptr;
}
int main()
{
Item items[10];
items[3]._ownerId = 20;
items[8]._rarity = 3;
FindByOwnerId f1;
f1._onwerId = 20;
FindByRarityId f2;
f2._rarity = 3;
FindItem(items, 10, f1);
FindItem(items, 10, f2);
return 0;
}
이렇게 해서 함수 포인터만의 단점을 템플릿과 함수 객체로 전부 처리할 수 있게 된다.
'C++ > 기초' 카테고리의 다른 글
[C++] STL - List (0) | 2023.12.04 |
---|---|
[C++] STL - Vector (1) | 2023.12.04 |
[C++] 함수 포인터 (0) | 2023.12.01 |
[C++] C++의 위험성과 메모리 관리의 위험성 (3) | 2023.11.29 |
[C++] 전방 선언 (0) | 2023.11.29 |