[C++] C++의 형변환
        
        
      
REF : 윤성우의 열혈 C++
C++의 형변환 연산
- C++에선 기존 C스타일의 형변환을 Old C-style 이라고 부른다, 단순히 호환성을 위해 존재한다.
 - 기존 C스타일의 형변환은 
형변환의 목적을 한 눈에 알아볼 수 없다.는 문제점이 존재한다. - 코드를 읽는사람으로 하여금 해당 형변환이 어떤 의도로 된것인지 쉽게 예측할 수 없기때문에 그렇다.
 - 이러한 논란과 문제점으로 인해 C++만의 형변환 연산자가 추가되었다.
 - C++만의 형변환 연산자와 규칙을 알아보자.
 
1. dynamic_cast
- 상속관계에서의 안전한 형 변환을 지원한다.
 유도클래스의 포인터와 참조형 데이터를기초 클래스의 포인터 및 참조형 데이터로형변환하는 경우(업캐스팅)#include <iostream> using namespace std; class Base { public: void VFnc(void) { cout<<"This is Base"<<endl; } }; class Derived : public Base { public: void VFnc(void) { cout<<"This is Derived!"<<endl; } }; int main(void) { Derived *ptr2 = new Derived; /*dynamic_cast upcasting*/ Base *base1 = dynamic_cast<Base *>(ptr2); base1->VFnc(); //"This is Base" }- Dynamic Cast로 업캐스팅을 하게되면, 기초클래스의 메서드를 호출하게된다.
 - 물론, 이때도 VFnc가 virtual로 선언되어있다면, 포인터형을보고 호출하는게 아닌, 내부 객체의 가상함수테이블에서 함수를 호출하므로, 유도클래스의 함수를 호출하게된다.
 
기초 클래스가 Polymorphic 클래스(가상함수가 있는 클래스)일때,유도클래스의 포인터 및 참조형 데이터로변환(다운캐스팅)class Base { public: virtual void VFnc(void) { cout<<"This is Base"<<endl; } }; class Derived : public Base { public: void VFnc(void) { cout<<"This is Derived!"<<endl; } }; int main(void) { Base *ptr1 = new Derived; /*dynamic_cast downcasting*/ Derived *derive1 = dynamic_cast<Derived *>(ptr1); }- Base클래스가 가상함수를 지닌 
Polymorphic 클래스이므로, Derived 클래스도Polymorphic이다. - 이런 Polymorphic 클래스를 업캐스팅하게되면 유도클래스의 포인터로 형변환할 수 있다.
 
- Base클래스가 가상함수를 지닌 
 
2. static_cast
- dynamic_cast보다 많은 형 변환을 허용한다.
 - 다운캐스팅, 업캐스팅을 자유롭게 사용할 수 있다.
 - 다양한 형태의 형변환을 허용하는데, 안정성을 위해서는 
dynamic_cast를 사용하고, 제한적인 상황에서만static_cast를 사용해야한다. 
#include <iostream>
using namespace std;
class Base
{
	public:
		void VFnc(void)
		{
			cout<<"This is Base"<<endl;
		}
};
class Derived : public Base
{
	public:
		void VFnc(void)
		{
			cout<<"This is Derived!"<<endl;
		}
};
int main(void)
{
	Base *base1 = new Derived;
	Derived *derive = static_cast<Derived *>(base1);
	derive->VFnc();
	Base *base2 = new Base;
	Derived *error = static_cast<Derived *>(base2);
	error->VFnc(); //"This is Derived!"
}
- 실제 내부 객체가 Derived인 포인터를 Derived로 형변환하는 것은 논리적으로 정당화될 수 있다.
 - 하지만, 내부 객체가 Base인 포인터를 Derived로 바꾸는 것은 정당화될 수 없다.
 - 실제로 현재 
error라는 포인터는 static_cast로는 컴파일 에러를 발생시키지 않는다. - 가상함수 테이블이 없으므로, 포인터형만으로 함수를 호출하게되는데, Derived 포인터이므로, Derived클래스의 VFnc를 호출하게된다.
    
- 실제 내부 객체가 base임에도 불구하고, 단순히 포인터형에 의해 이를 호출하는 것은 논리적으로 말이 안된다.
 
 - 하지만, dynamic cast로 형변환을 하게되면 현재 Base가 
Polymorphic하지 않으므로, 컴파일에러를 발생시킨다. - 이를 막기위해 Base클래스의 메서드 중 하나를 virtual로 선언해주면 되긴하나, 
dynamic_cast 연산자는 형변환하고자하는 대상 객체가 아닐경우, NULL을 반환한다.- 만약 참조형일 경우, 
bad_cast exception이 발생한다. 
#include <iostream> using namespace std; class Base { public: virtual void VFnc(void) { cout<<"This is Base"<<endl; } }; class Derived : public Base { public: void VFnc(void) { cout<<"This is Derived!"<<endl; } }; int main(void) { Base *base2 = new Base; Derived *error = dynamic_cast<Derived *>(base2); //Null 반환 if (!error) return 0; }- dynamic_cast는 컴파일시간이 아닌, 프로그램이 실행될때의 안정성을 검사하기때문에, static_cast보다 실행속도는 느리지만 안정적인 형변환이 가능하다.
 - 이러한 기능을 RTTI라고하며, dynamic_cast와 RTTI를 참고하자
 - 이렇듯, static_cast보다 dynamic_cast가 보다 안전한 형변환을 할 수 있으므로, 제한적이 상황에서만 static_cast를 사용해야한다.
 
 - 만약 참조형일 경우, 
 
- 다만, static_cast가 유용하게 사용되는 경우가 있는데, 
기본 자료형 간의 형 변환이다. - int, float, double 등 데이터의 형변환을 할 때 사용되는데, static_cast가 C의 형변환과 다른 점은
 포인터간의 형변환을 허용하지 않는다.는 점이다.
#include <iostream>
int main(void)
{
	int num = 0;
	int *p1 = #
	
	float *e1 = static_cast<float *>(p1);//컴파일 에러
	float *e2 = (float *)p1;
	return 0;
}
- 실제로, 이 코드를 실행해보면, 포인터를 다른 포인터로 형변환하는 행위는 불가능하다.
 - 이렇게 static_cast가 
기본 자료형간 형변환,상속관계의 클래스와 포인터의 형변환만을 허용하므로, 프로그래머는 이 둘 중 하나를 파악할 수 있다. 
3. const_cast
- const 성향을 삭제하는 캐스팅
 - const의 성향을 삭제하는 것이 const의 가치를 떨어뜨린다고 생각할수도 있지만, 나름의 이유가 있다.
    
- 함수의 인자 전달 시, const 선언으로 인한 형불일치를 수정해준다.
 - 라이브러리 함수를 사용할때, const형이 맞지 않을 때 제한적으로 사용하는 것이 좋다.
 
 
4. reinterpret_cast
- 상관없는 자료형으로의 형변환
 
#include <iostream>
using namespace std;
int main(void)
{
	int num = 1;
	char *ptr = reinterpret_cast<char *>(&num);
	for (int i = 0; i < sizeof(num); i++)
	{
		cout<<static_cast<int>(*(ptr + i))<<endl;
	}
	return 0;
}
- 정수자료형 int가 4바이트로 숫자를 표현한다.
 - 이를 1바이트단위로 접근할 수 있도록 char *로 변환해서 1바이트씩 값을 읽어온다.
 - 이러한 reinterpret_cast의 사용은 주소값 출력에도 이용될 수 있다.
 - C에서는 포인터의 주소를 출력하기위해서는 포인터의 형을 long long으로 형변환했어야했는데, reinterpret캐스팅로 이것이 가능하다.
 
댓글남기기