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

복사 생성자와 복사 대입 연산자는 정의하지 않아도 컴파일러가 암시적으로 만들어준다.

이 경우 얕은 복사가 일어난다.

 

얕은 복사 (Shallow Copy)

멤버 데이터를 비트열 단위로 똑같이 복사한다. (메모리 영역 값을 그대로 복사)

기본 복사 생성자나 기본 복사 대입 연산자는 값을 그대로 복사해준다.

 

깊은 복사 (Deep copy)

멤버 테이터가 참조(주소) 값이라면 데이터를 새로 만들어준다. (원본 객체가 참조하는 대상까지 새로 만들어서 복사)

 

복사 생성자를 암시적으로 사용하는 경우에는 부모 클래스와 멤버 클래스의 복사 생성자가 호출되지만, 명시적으로 사용하는 경우 부모 클래스와 멤버 클래스의 기본 생성자가 호출된다.

명시적으로 사용 시 부모와 멤버 클래스의 복사 생성자를 호출하기 원한다면 초기화 리스트에서 지정해 주어야 한다.

 

암시적 복사 생성자와 복사 대입 연산자

  1. 부모 클래스의 복사 생성자 호출
  2. 멤버 클래스의 복사 생성자 호출
  3. 멤버가 기본 타입일 경우 메모리 복사 (얕은 복사)

 

명시적 복사 생성자

  1. 부모 클래스의 기본 생성자 호출
  2. 멤버 클래스의 기본 생성자 호출
// 복사 생성자를 명시적으로 선언한 경우에는,
// 부모 클래스나 멤버 클래스의 복사 생성자를 초기화 리스트로 호출해주어야 한다.
Knight(const Knight& knight) : Player(knight), _pet(knight._pet)
{
    cout << "Knight(const Knight&)" << endl;
    _hp = knight._hp;
}

 

명시적 복사 대입 연산자 : 아무것도 해주지 않는다.

// 복사 대입 연산자를 명시적으로 선언한 경우에는,
// 부모 클래스와 멤버 클래스의 복사 대입 연산자를 호출해주어야 한다.
Knight& operator=(const Knight& knight)
{
    cout << "opeator=(const Knight&)" << endl;
    Player::operator=(knight);
    _pet = knight._pet;
    _hp = knight._hp;
    return *this;
}

 

깊은 복사를 선택하게 되는 경우 필연적으로 명시적인 복사 생성자 또는 복사 대입 연산자가 필요하게 되는데, 그 순간 모든 책임은 프로그래머에게 위임된다.

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

전방선언  (0) 2022.08.29
[동적 할당] 캐스팅 4총사  (0) 2022.08.29
[동적 할당] 타입 변환  (0) 2022.08.29
[동적 할당] 동적 할당  (0) 2022.08.28
[객체지향 여행]  (0) 2022.08.28

+ Recent posts