게임 개발/C++

[C++] 캐스팅 - 3. dynamic_cast

유행성바코드 2025. 3. 6. 14:30

목차

  • 01. Intro
  • 02. dynamic_cast
    • 정의 및 특징
    • 예시
    • 성능
  • 03. 마무리
  • 04. 연관 내용

01. Intro

오늘은 C++ 스타일 캐스팅 중에서 dynamic_cast에 대해 알아보겠습니다.

 


02. dynamic_cast

정의 및 특징

dynamic_cast는 런타임 타임에서 형 변환을 한 번 검사한 후에 변환을 수행합니다.

여담으로 static_cast는 컴파일 타임에서 형 변환을 검사한 후에 변환을 수행합니다.

 

dynamic_cast는 런타임에서 형 변환을 진행하기 때문에, 반드시 클래스 내에 가상 함수가 하나 이상은 반드시 필요합니다.

아무래도, 런타임에서 검사를 진행하기에 가상 함수 테이블과 가상 함수 테이블 포인터가 필요하기 때문입니다.

 

vtable과 vptr을 통해 원본 클래스에 접근할 수 있어 static_cast와 달리 다운 캐스팅이 안정적입니다.

만약에, 원본 클래스가 형 변환할 클래스와 일치하지 않는 경우에는 nullptr을 반환합니다. 

 

그렇다면, 하나씩 살펴보도록 하겠습니다.

 

예시

1. 다운 캐스팅 성공 예시

#include <iostream>

using namespace std;

// 부모 클래스
class Sport
{
public:
	Sport() : _num(0) {}
	// 가상 소멸자
	virtual ~Sport() {}

	int _num;
};

// 자식 클래스 1
class Soccer : public Sport
{
public:
	Soccer() : _player(22) {}
	~Soccer() {}

	int _player;
};

// 자식 클래스 2
class Baseball : public Sport
{
public:
	Baseball() : _team(10) {}
	~Baseball() {}

	int _team;
};

int main()
{
	Sport* sport = new Baseball();
	Baseball* baseball = dynamic_cast<Baseball*>(sport);

	// Baseball 클래스 일 때
	if (baseball)
	{
		cout << "baseball class" << endl;
	}
	// Baseball 클래스가 아님
	else
	{
		cout << "non-baseball class" << endl;
	}

	return 0;
}

dynamic_cast를 진행하기 위해, 가상 소멸자를 선언했습니다.

sport 포인터 변수에 Baseball 클래스 객체를 동적 할당해 가리키도록 했습니다.

 

다시, sport 포인터 변수가 가리키고 있는 객체는 Baseball 클래스의 객체이고 Baseball 클래스는 가상 함수가 있기에 dynamic_cast로 형 변환을 진행할 수 있습니다.

그래서, 위 코드를 실행했을 때, 위 사진과 같은 결과가 나옵니다.

 

if(baseball) // if(baseball != nullptr)

if(baseball) 조건문은 baseball이 nullptr이 아닐 때, 조건문을 통과하게 됩니다.

dynamic_cast에서 nullptr이 반환되려면, 잘못된 형 변환을 진행할 경우에만 반환됩니다.

 

2. 다운 캐스팅 실패 예시

#include <iostream>

using namespace std;

// 부모 클래스
class Sport
{
public:
	Sport() : _num(0) {}
	// 가상 소멸자
	virtual ~Sport() {}

	int _num;
};

// 자식 클래스 1
class Soccer : public Sport
{
public:
	Soccer() : _player(22) {}
	~Soccer() {}

	int _player;
};

// 자식 클래스 2
class Baseball : public Sport
{
public:
	Baseball() : _team(10) {}
	~Baseball() {}

	int _team;
};

int main()
{
	Sport* sport = new Soccer();
	Baseball* baseball = dynamic_cast<Baseball*>(sport);

	// Baseball 클래스 일 때
	if (baseball)
	{
		cout << "baseball class" << endl;
	}
	// Baseball 클래스가 아님
	else
	{
		cout << "non-baseball class" << endl;
	}

	return 0;
}

이전 코드와 달리 이번에는 sport 포인터 변수에 Soccer 클래스 객체를 동적 할당받아 해당 주소를 넣었습니다.

 

Soccer 클래스 객체는 Baseball 클래스가 아니므로 nullptr이 반환되어 if(baseball) 조건문에 통과하지 못했습니다.

정말로 nullptr이 반환되는지 조사식을 통해 확인해 보겠습니다.

 

조사식에서 baseball 포인터 변수의 주소가 nullptr을 확인했습니다.

 

3. 참조 변환

참조 변환을 할 때, 실패하면, std::bad_cast 예외가 발생합니다.

 

int main()
{
	// Baseball 클래스 객체를 레퍼런스로 담기
	Baseball baseball;
	Sport& sportRef = baseball;

	try
	{
		Baseball& baseballRef = dynamic_cast<Baseball&>(sportRef);
		
		cout << "dynamic cast - success!" << endl;
	}
	catch (const bad_cast& e)
	{
		cout << "dynamic cast - failure!" << endl;
	}

	return 0;
}

위에 클래스 선언 및 구현 코드는 동일하므로 생략하겠습니다.

Baseball 클래스 객체를 래퍼런스로 담은 baseball 변수를 dynamic_cast<Baseball&>로 하니 정상적으로 통과했습니다.

 

 

int main()
{
	// Soccer 클래스 객체를 레퍼런스로 담기
	Soccer soccer;
	Sport& sportRef = soccer;

	try
	{
		Baseball& baseballRef = dynamic_cast<Baseball&>(sportRef);
		
		cout << "dynamic cast - success!" << endl;
	}
	catch (const bad_cast& e)
	{
		cout << "dynamic cast - failure!" << endl;
	}

	return 0;
}

Soccer 클래스 객체를 래퍼런스로 담은 soccer 변수를 dynamic_cast<Baseball&>로 하니 std::bad_cast 오류가 발생했습니다.

 

 

성능

dynamic_cast는 vptr을 통해 원본 클래스를 찾으므로 static_cast가 dynamic_cast보다 성능이 미세하게 더 좋습니다.

그래서, 자식 클래스의 정보를 담는 멤버 변수를 부모 클래스에서 저장합니다.

해당 멤버 변수를 통해 자식 클래스의 정보를 얻어 static_cast를 진행하기도 합니다.

 

 


03. 마무리

오늘은 dynamic_cast에 대해서 알아보았습니다.

내일은 C++ 스타일 캐스팅의 세 번째 방법인 const_cast에 대해서 알아보겠습니다.

 

 


04. 연관 내용

  • [C++] 캐스팅 - 1. C 스타일 캐스팅
 

[C++] 캐스팅 - 1. C 스타일 캐스팅

목차01. Intro02. 캐스팅C 스타일 캐스팅C++ 스타일 캐스팅03. C 스타일 캐스팅사용 예시C 스타일 캐스팅 지양 이유04. 마무리05. 연관 내용01. Intro오늘은 캐스팅(Casting)과 C스타일 캐스팅에 대해서 알아

epidemic-barcode.tistory.com

  • [C++] 캐스팅 - 2. static_cast
 

[C++] 캐스팅 - 2. static_cast

목차01. Intro02. static_cast사용 예시C 스타일 캐스팅 vs static_cast03. 마무리04. 연관 내용01. Intro오늘은 C++ 스타일 캐스팅 중에서 static_cast에 대해 알아보겠습니다. 02. static_caststatic_cast는 C++ 스타일 캐

epidemic-barcode.tistory.com

  • [C++] 캐스팅 - 4. const_cast
 

[C++] 캐스팅 - 4. const_cast

목차01. Intro02. const_cast정의 및 특징사용 예시주의점03. 마무리04. 연관 내용01. Intro오늘은 C++ 스타일 캐스팅 중에서 const_cast에 대해 알아보겠습니다.  02. const_cast 정의 및 특징const_cast는 const 속

epidemic-barcode.tistory.com

  • [C++] 캐스팅 - 5. reinterpret_cast
 

[C++] 캐스팅 - 5. reinterpret_cast

목차01. Intro02. reinterpret_cast정의 및 특징사용 예시03. 마무리04. 연관 내용01. Intro오늘은 C++ 스타일 캐스팅 중 마지막인 reinterpret_cast에 대해 알아보겠습니다. 02. reinterpret_cast정의 및 특징reinterpret_c

epidemic-barcode.tistory.com

 


 

읽어주셔서 감사합니다.

틀린 내용 지적은 언제나 환영입니다!