이 전까지만 공부해도 언리얼을 활용할 수 있다.
서버쪽에서는 STL이라는게 필요한데, 이를 공부하기 전 사전 지식을 쌓아보자. 또한 면접에서 STL관련 질문도 나오기 때문에 공부해두자.
typedef
typedef는 특정 자료형에 가명을 만드는 것이다.
typedef int DATA;
DATA number = 1;
여기서 정수형 자료형 int의 이름을 DATA로 지어주면, int 대신 DATA로 정수를 받는 변수를 만들 수 있다.
참고로 만들어진 선언 문법의 맨 앞에 typedef를 붙인다고 생각하는게 문법적으로 이해하기 편하다.
밑의 두 가지 중에서 무엇이 맞는 문법일까?
typedef int[20] ARRAY;
typedef int ARRAY[20];
정답은 밑의 코드가 맞는 문법이다. 이해하기 편한 것은 위다. int형 원소가 20개 있는 배열을 앞으로 ARRAY라고 부른다라고 생각할 수 있기 때문이다. 하지만 위 코드는 틀렸고, 밑의 코드가 맞다.
앞서 말했듯이 typedef는 선언 문법(int ARRAY[20];)에 typedef를 앞에 붙인 것이기 때문이다.
이러한 개념을 함수에도 사용할 수 있다.
함수 포인터
먼저 함수의 이름은 함수의 시작 주소를 나타낸다는 것을 알아야 한다. 배열과 유사한 방식으로 함수를 호출하는 것이다.
하지만 함수는 배열처럼 메모리에 저장되는 것이 아니다. 함수는 컴파일될 때 함수의 내용이 code영역에 들어가고, 함수 포인터는 code영역에 있는 함수의 시작 주소를 가리키고 있을 뿐이다.
전역 및 정적 함수 포인터
int Add(int a, int b)
{
return a + b;
}
int Sub(int a, int b)
{
return a - b;
}
두개의 정수형 인자를 받고 정수를 반환하는 함수 Add, Sub가 있다고 하자. 앞서 얘기한 자료형에 가명을 씌우는 것처럼 함수에도 가명을 지어줄 수 있다.
typedef int(FUNC_TYPE)(int a, int b);
이제부터 int형 인자를 2개 받고, int형 데이터를 반환하는 함수의 틀을 FUNC_TYPE이라고 선언한다.
FUNC_TYPE* fn;
fn = Add; // 또는 fn = Sub;
// &Add에서 &을 생략한 것
int result = fn(1, 2); // == (*fn)(1, 2);
함수 포인터 fn는 FUNC_TYPE의 틀을 가진 함수의 주소를 저장할 수 있다. 따라서 Add와 Sub를 저장할 수 있으며, result는 fn이 가진 함수의 주소가 바뀌더라도 수정하지 않고 그대로 사용할 수 있다. 또한 다른 함수의 인자로 들어갈 수도 있다.
int (*fn)(int, int);
typedef int(FUNC_TYPE)(int, int);
FUNC_TYPE* fn;
참고로 둘 다 같은 의미지만, 첫 번째 방법이 실제로 많이 쓰인다.
typedef bool(ITEM_SELECTOR)(Item* item);
Item* FindItem(Item items[], int itemCount, ITEM_SELECTOR* selector)
{
for (int i = 0; i < itemCount; i++)
{
Item* item = &items[i];
// selector가 true면 item을 반환
if (selector(item))
return item;
}
return nullptr;
}
ITEM_SELECTOR는 함수의 틀을 나타내는 가명이다. Item*를 인자로 받고 bool 값을 반환한다.
FindItem에 함수 포인터인 selector를 인자로 받고 있는데, 여기서 함수 포인터의 사용법을 알 수 있다. 동작을 함수의 인자로 넘겨주고 싶을 때 사용하는 것이다.
bool IsRareItem(Item* item)
{
return item->_rarity >= 2;
}
int main()
{
Item item[10] = {};
item[3]._rarity = 2;
Item* rareItem = FindItem(item, 10, IsRareItem);
}
ITEM_SELECTOR와 같은 틀을 가진 함수 IsRareItem은 FindItem의 인자로 들어갈 수 있다. 위에서 말한 것처럼 IsRareItem은 희귀한 아이템을 찾을 때 사용하는 함수 인자다. 만약 검색한 단어와 같은 아이템, 공격력이 높이 아이템 등 다른 아이템을 찾는 함수를 넣고 싶다면, ITEM_SELECTOR와 같은 틀을 가지도록 각 함수를 정의하고 인자로 넣어주면 된다.
멤버 함수 포인터
fn = &Add;
위에서 함수 포인터를 살펴볼때, &을 생략했었다. 하지만 이제부터 생략하지 않는 것이 좋다.
class Knight
{
public:
// 멤버 함수
int GetHp()
{
return _hp;
}
public:
int _hp = 100;
};
이때까지 배운 함수 포인터 문법은 전역 및 정적 함수만 담을 수 있다. 하지만 객체를 기반으로 호출되는 멤버함수는 같은 방식으로 담을 수 없다.
typedef int(*FUNC)(int, int); // 일반 함수 포인터
typedef int(Knight::*MEMFUNC)(); // 멤버 함수 포인터
일반적인 함수 포인터를 해석해보면,
[int(*)(int, int)] -> int형 인자를 2개 받고 int형 데이터를 반환하는 함수를
[FUNC] -> FUNC라는 이름으로
[typedef] -> 부른다.
멤버 함수 포인터를 해석해보면,
[int(Knight::*)()] -> 인자를 받지 않고 int형 데이터를 반환하는 Knight의 멤버 함수를
[MEMFUNC] -> MEMFUNC라는 이름으로
[typedef] -> 부른다.
FUNC fn;
fn = &Add;
fn(1, 2);
Knight k;
MEMFUNC mfn;
mfn = &Knight::GetHp;
(k.*mfn)();
Knight* k2 = new Knight();
((*k2).*mfn)();
(k2->*mfn)();
delete k2;
이때 멤버 함수 포인터는 멤버 함수의 주소를 받을 때 &을 생략할 수 없다.
동적 할당으로 k2를 만들었을 때는 k2의 객체 주소에 있는 Knight 클래스에 속한 GetHp 함수 주소를 가져와서 사용한다.
출처
https://www.inflearn.com/course/%EC%96%B8%EB%A6%AC%EC%96%BC-3d-mmorpg-1/dashboard
[C++과 언리얼로 만드는 MMORPG 게임 개발 시리즈] Part1: C++ 프로그래밍 입문 - 인프런 | 강의
시리즈를 원활하게 학습하기 위한 기초적인 C++ 문법들에 대해 학습합니다. 어셈블리 언어부터 시작해서 기본 C++ 문법, STL, C++11까지 핵심적인 내용을 압축해서 다루게 됩니다., - 강의 소개 | 인
www.inflearn.com
'프로그래머 > CPP_강의정리' 카테고리의 다른 글
cpp 템플릿 기초 (0) | 2021.10.06 |
---|---|
cpp 함수 객체 (0) | 2021.10.06 |
cpp 디버깅 기초 (0) | 2021.09.28 |
cpp casting의 4가지 방법 (0) | 2021.09.27 |
cpp 얕은 복사와 깊은 복사 (0) | 2021.09.23 |