함수 포인터 + 함수 객체 + 템플릿을 모두 활용한다.

 

class Item
{
public:

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;
};

Item* FindItem(Item items[], int itemCount, FindByOwnerId selector) // 확장성이 떨어짐
{
	for (int i = 0; i < itemCount; i++)
	{
		Item* item = &items[i];

		if (selector(item)) return item;
	}
	return nullptr;
}

 

위와같은 경우 FindItem의 세번째 인자로 함수 객체를 넘겨주는데, 같은 형식의 함수 객체를 커버하지 못해서 확장성이 떨어진다.

그렇다고 부모 클래스를 만들어서 업캐스팅을 하는 것 보다는 템플릿을 이용하면 더 깔끔하게 처리가 된다.

 

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;
}

 

 

'C++ > Rookiss C++' 카테고리의 다른 글

[STL] list  (0) 2022.08.31
[STL] vector  (0) 2022.08.30
[콜백 함수] 템플릿 기초  (0) 2022.08.30
[콜백 함수] 함수 객체  (0) 2022.08.30
[콜백 함수] 함수 포인터  (0) 2022.08.30

함수나 클래스를 찍어내는 틀. 함수 템플릿과 클래스 템플릿이 있다.

 

template<typename T>
template<class T> // 둘다 사용 가능함

 

함수 템플릿

 

template<typename T>
void Print(T a) { // do something }

Print(50); // 암시적
Print<int>(50); // 명시적

 

인자가 2개인 경우도 사용 가능하다.

template<typename T1, typename T2>
void Print(T1 a, T2 b)
{
	// do something
}

 

템플릿 특수화

특정 타입에 대해서만 다른 규칙을 따르도록 하고 싶을 때 사용한다 (예외 적용)

template<typename T>
void Print(T a)
{
	// do something
}

template<>
void Print(Knight a)
{
	// do something
}

 

클래스 템플릿

 

template<typename T>
class RandomBox
{
public:
	T GetRandomData()
	{
		int idx = rand() % 10;
		return _data[idx];
	}

public:

	T _data[10];
};

 

무조건 typename만 붙여줘야 하는 것은 아니다.

template<typename T, int SIZE = 10> // 기본값 설정 가능
class RandomBox
{
public:
	T GetRandomData()
	{
		int idx = rand() % SIZE;
		return _data[idx];
	}

public:

	T _data[SIZE];
};

 

단, 템플릿 인자가 다른 경우 서로 별개의 클래스로 보기때문에 클래스 이름이 같아보여도 다형성이 성립하지 않는다.

인자까지 같아야만 같은 클래스로 인식한다.

RandomBox<int, 10> rb1;
RandomBox<int, 20> rb2;
rb1 = rb2 // 불가능!

 

템플릿 특수화

template<int SIZE = 10>
class RandomBox<double, SIZE>
{
public:
	double GetRandomData()
	{
		int idx = rand() % SIZE;
		return _data[idx];
	}

public:

	double _data[SIZE];
};

 

함수는 오버로딩이 지원되기 때문에 이름이 같아도 상관 없었지만 클래스는 그렇지 않기때문에 템플릿 특수화 라는것을 명시하기 위해 클래스명에 추가로 명시를 한다.

 

'C++ > Rookiss C++' 카테고리의 다른 글

[STL] vector  (0) 2022.08.30
[콜백 함수] 콜백 함수  (0) 2022.08.30
[콜백 함수] 함수 객체  (0) 2022.08.30
[콜백 함수] 함수 포인터  (0) 2022.08.30
[디버깅]  (0) 2022.08.30

함수처럼 동작하는 객체

 

함수 포인터의 단점

1) 시그니처가 안 맞으면 사용할 수 없다.

2) 상태를 가질 수 없다.

 

함수 객체를 사용하려면 () 연산자 오버로딩을 해야 한다.

 

class Functor
{
public:
	void operator()() { // do something }
private:
	int _value = 0;
};

Functor functor;
functor(); // 함수처럼 사용 가능

 

STL에서 함수 객체를 자주 사용한다.

 

MMO에서 함수 객체를 많이 사용한다.

예를 들어, 서버에 캐릭터 이동 요청이 많으면 순차적으로 처리하는데, 그 요청들을 객체화 시켜서 큐에 넣어둘 수 있다.

 

함수 포인터와는 다르게 함수 객체를 만들어주는 시점과 실제 실행하는 시점을 분리시킬 수 있다.

차후 커맨드 패턴이라는 것으로 배울 수 있다.

 

개념 자체는 단순하다. 어떤 객체를 만들어서 연산자 오버로딩을 통해서 함수처럼 동작하는 객체를 만드는것이다.

'C++ > Rookiss C++' 카테고리의 다른 글

[콜백 함수] 콜백 함수  (0) 2022.08.30
[콜백 함수] 템플릿 기초  (0) 2022.08.30
[콜백 함수] 함수 포인터  (0) 2022.08.30
[디버깅]  (0) 2022.08.30
전방선언  (0) 2022.08.29

typedef를 통해 타입을 재정의 했던 것처럼 함수도 타입을 재정의 할 수 있다.

 

// 반환값(이름)(매개변수)
typedef int(FUNC_TYPE)(int, int);

 

함수의 이름은 함수의 시작 주소를 들고있는것과 같다. (마치 배열과 유사함)

 

FUNC_TYPE* fn;
fn = Add;

int result = fn(1, 2);
int result2 = (*fn)(1, 2); // 둘다 완벽하게 동일하게 동작

 

재정의가 된 함수는 기존의 포인터 변수처럼 사용할 수 있다.

함수 포인터는 *(접근 연산자)이 붙어도 함수 주소에 접근한다.

 

함수 포인터는 함수의 인자로 건네줄 수도 있다. 동작 자체를 넘겨주는 것과 같다.

인자로 넘겨주는 경우 따로 재정의를 하지 않고 매개변수에서 바로 선언할 수 있다.

 

Item* FindItem(Item* items, bool(*selector)(Item* item)) // FUNC_TYPE* selector
{
	// ..
}

 

재정의를 했는데 포인터를 붙이지 않고 사용하는 것은 전방선언만 해놓은 것을 사용하겠다고 하는것과 같기 때문에 컴파일 오류가 발생한다. 실제로 메모리에도 잡히지 않는다.

 

보통은 포인터까지 붙여서 한번에 재정의를 하는 편이다.

 

typedef int(*PFUNC)(int, int);

 

다만 여태까지의 문법으로는 전역 함수와 정적 함수만 담을 수 있다. (호출 규약이 동일한 것들)

멤버 함수는 자기 자신의 객체를 넘겨주는것부터 시작하기 때문에 호출 규약이 맞지 않다.

 

typedef int(Knight::*PMEMFUNC)(int, int);

 

멤버 함수 포인터는 이렇게 선언할 수 있다.

사용은 조금 복잡한 편이다.

 

Knight k1;

PMENFUNC mfn;
mfn = &Knight::GetHP; // 반드시 &를 붙여주어야 한다

(k1.*mfn)(1, 2); // 반드시 *을 붙여주어야 한다

'C++ > Rookiss C++' 카테고리의 다른 글

[콜백 함수] 템플릿 기초  (0) 2022.08.30
[콜백 함수] 함수 객체  (0) 2022.08.30
[디버깅]  (0) 2022.08.30
전방선언  (0) 2022.08.29
[동적 할당] 캐스팅 4총사  (0) 2022.08.29

단축키

 

F5 : 디버깅 시작

Shift+F5 : 디버깅 중지

F9 : 중단점 지정

F10 : 프로시저 단위 실행 (한 줄씩 실행하는데 함수 내부까지 들어가지 않음)

F11 : 한 단계씩 코드 실행 (한 줄씩 실행하고 함수를 만나면 내부까지 들어감)

 

조사식을 통해 실시간으로 값을 변경할 수 있다.

 

중단점을 여러개 걸고 디버그 시에는 F5를 눌러서 중단점 단위로 실행할 수 있다.

 

호출 스택을 통해 어떤 함수들을 타고 넘어왔는지 확인할 수 있다.

 

조건부 중단점

특정 조건이 만족하는 경우만 중단점이 실행되도록 할 수 있다.

 

중단점에 작업이라는것을 걸 수 있는데, 출력창에 로그를 출력시킬 수 있다.

 

중단점에 걸린 화살표를 옮겨서 코드의 흐름을 조작할 수 있다.

 

 

 

크래시가 발생하면 호출 스택을 살펴서 어느부분에서 문제가 터졌는지 우선 확인한다.

'C++ > Rookiss C++' 카테고리의 다른 글

[콜백 함수] 함수 객체  (0) 2022.08.30
[콜백 함수] 함수 포인터  (0) 2022.08.30
전방선언  (0) 2022.08.29
[동적 할당] 캐스팅 4총사  (0) 2022.08.29
[동적 할당] 얕은 복사 vs 깊은 복사  (0) 2022.08.29

+ Recent posts