C++ 캐스팅
모두의 코드 내용을 공부하고 정리한 내용입니다.
업 캐스팅
부모 클래스의 포인터가 자식클래스를 가리킨다.
Parent *pp = &cp // cp는 자식 클래스 객체
-
자식 클래스는 부모 클래스로 부터 상속을 받으니 부모 클래스의 생성자를 불러와 올바르게 타입을 만들어 낼 수 있다.
-
하지만 부모 클래스형 포인트이기에 부모 클래스 정보밖에 없다.
- 그냥 자식이 가지고 있는 부모의 정보를 가리킨다.
- 따라서 자식 클래스만 가지고 있는 기능들을 사용할 수 없다.
다운 캐스팅
업 캐스팅과 반대로 부모 클래스는 자식의 정보를 가지지 않는데 없는 정보를 가리키는 포인터를 생성해서다.
Children *pc = &pp
은 오류가 난다. // pp는 부모 클래스 객체- 자식 클래스의 생성자를 어떻게 호출할껀데? 제대로된 포인터 생성이 이루어지지 않는다.
- 물론 어떻게 자식클래스를 부모클래스에 넣고 그 클래스를 다시 자식에게 넣고 강제적으로 다운 캐스팅하면 되긴하는데 컴파일해도 프로그램이 멈출 수 있다.
- 그런데 이 오류를 컴파일러가 잡아내기 어려워서 하면 안되는 작업이다.
C언어 캐스팅
- C언어의 캐스팅에 암시적 그리고 명시적 캐스팅이 있다
- 컴파일러가 알아서 하는 암시적 캐스팅, 우리가 직접하는 명시적 캐스팅
그런데 명시적 캐스팅에서 몇가지 문제점이 있다.
- 적절하지 않은 방식으로 캐스팅을 해도 컴파일 오류가 발생하지 않는다.
- 가독성이 떨어진다.
- 캐스팅의 의미를 파악하기가 힘들다.
int_value = (int)float_value; // 데이터 손실실
function((int)float_value) // 가독성 및 의미 파악하기 힘들다
-
C++에서는 상황에 맞는 잘 작동하는 캐스팅이 존재한다.
-
아래 4가지 모두 형태는 (원하는 캐스팅 종류)<바꾸려는 타입="">(무엇을 바꿀 것인가?)바꾸려는>
static_cast
- C언어에서 수행하던 문제없던 캐스팅
- 포인터형을 변환할 때 다른 타입으로는 변경 불가능
ex) int* a = int형 데이터 ==> 가능
ex) int* a = double형 데이터 ==> 불가능
- 하지만 상속 관계에 있는 포인터 끼리는 가능하다.
const_cast
-
객체의 상수성(const)를 없애는 타입 변환 ex) cosnt int 가 int로 변환됨
-
함수 포인터에 대해서는 사용 불가능 ==> 컴파일 에러
dynamic_cast
- 부모 클래스 포인터 에서 자식 클래스 포인터로 다운 캐스팅을 안전하게 수행
- 올바르지 않게 사용시 에러가 뜬다.
- 위의 다운 캐스팅에 따른 오류를 방지.
Children* pc = dyanmic_cast<Children*>(pp); // 컴파일 에러 발생
- 캐스팅을 성공하면 target_type 형식의 값을 반환
- 실패시 target_tpye이 포인터 형식이면 해당 형식의 nullptr 반환
- 실패시 target_tpye에 대한 레퍼런스인 경우 예외 발생(bad_cast)
대상 포인터가 무엇을 가리키냐에 따라 다르게 반응한다.
- 자기 자식을 가리키는 부모 포인터를 자식 클래스로 캐스팅
- 해당 부모 클래스는 결국 자식 클래스를 가리키므로 캐스팅 가능
class Base
{
public:
int m_i = 0;
virtual void print()
{
cout << "I'm Base" << endl;
}
};
class Derived1 : public Base
{
public:
int m_j = 1024;
virtual void print() override
{
cout << "I'm derived_1" << endl;
}
};
class Derived2 : public Base
{
public:
string m_name = "Dr. Two";
virtual void print() override
{
cout << "I'm derived_2" << endl;
}
};
int main()
{
Derived1 d1;
Base *base = &d1;
auto *base_to_d1 = dynamic_cast<Derived1*>(base);
cout << base_to_d1->m_j << endl;
return 0;
}
부모 클래스를 가리키는 부모 포인터 또는 캐스팅타입과 다른 타입을 가르킬 때 자식 클래스로 캐스팅
- 자식 클래스만의 정보, 없는 정보를 가리키려고 하니 오류 또는 nullptr 반환
int main()
{
Derived1 d1;
Base * base = &d1;
auto *base_to_d1 = dynamic_cast<Derived2*>(base);
if (base_to_d1 != nullptr)
cout << base_to_d1->m_name << endl;
else
cout << "Failed" << endl;
return 0;
} // 해당 예시는 포인트 형식이므로 nullptr 반환
reinterpret_cast
- 위험을 감수하고 하는 캐스팅으로 서로 관련이 없는 포인터들 사이의캐스팅
- 다른 형태의 포인터로 바꾸기 때문에 예상치 못한 결과가 나올 수 있다.
형변환이 이루어지면 해당 자료형의 bit수에 맞게 들어간다.
- 작은 bit로 구성된 자료형에 들어가면 원래 크기를 다 표현하지 못함.
- 큰 bit로 구성된 자료형에 들어가면 데이터가 그대로 유지
개인 공부 기록용 블로그입니다.
틀린 부분 있으다면 지적해주시면 감사하겠습니다!!
댓글남기기