함수처럼 동작하는 객체

 

함수 포인터의 단점

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

전방선언 : 식별자를 정의하기 전에 식별자의 존재를 컴파일러에게 알리는 것

헤더 포함 의존성을 최소화하기 위해 사용한다.

 

class Game
{
public:
	Game() {}
	~Game() {}

private:
	Player* _player; // Player 헤더가 없으면 컴파일이 불가능
};

 

class Player; // 나중에 정의하겠다고 전방선언

class Game
{
public:
	Game() {}
	~Game() {}

private:
	Player* _player;
    // 최상단 줄을 지우고 class Player* _player 와 같은 형태도 가능하다.
};

 

물론 헤더파일을 포함시키면 해결 되지만, include의 의존성을 줄임으로써 빌드 시간을 줄일 수 있다.

멤버 변수로 선언시에는 포인터인 경우만 가능하고 리턴 타입이나 매개 변수의 경우 객체 타입으로 사용할 수 있다.

 

단, 동적 할당이나 호출하는 경우는 데이터 구조를 모르기때문에 오류가 발생하게 된다.

 

"해당 클래스는 몇 바이트인가?" 라는 질문을 던져보면 알 수 있다.

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

[콜백 함수] 함수 포인터  (0) 2022.08.30
[디버깅]  (0) 2022.08.30
[동적 할당] 캐스팅 4총사  (0) 2022.08.29
[동적 할당] 얕은 복사 vs 깊은 복사  (0) 2022.08.29
[동적 할당] 타입 변환  (0) 2022.08.29

면접에서 매번 나오는 단골 질문이다.

 

static_cast

타입 원칙에 비춰볼 때 상식적인 캐스팅만 허용해준다. C스타일의 타입 변환을 대체한다고 보면 된다.

ex) int <-> float, 다운 캐스팅

 

dynamic_cast

상속 관계에서의 안전한 형 변환을 지원한다.

RTTI(Runtime Type Information). 다형성을 활용한다. 즉, 가상 함수가 존재하는 클래스에만 사용할 수 있다.

vftable을 이용한다.

만약 잘못된 타입으로 캐스팅 시, nullptr을 반환해준다.

 

const_cast

const를 붙이거나 뗄 때 사용한다.

사용할 일은 거의 없다고 보면 된다.

 

reinterpret_cast

가장 위험하고 강력한 형태의 캐스팅.

ex) 포인터랑 전혀 관계없는 다른 타입 변환 등

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

[디버깅]  (0) 2022.08.30
전방선언  (0) 2022.08.29
[동적 할당] 얕은 복사 vs 깊은 복사  (0) 2022.08.29
[동적 할당] 타입 변환  (0) 2022.08.29
[동적 할당] 동적 할당  (0) 2022.08.28

+ Recent posts