모두의 코드 내용을 공부하고 정리한 내용입니다.



업 캐스팅

부모 클래스의 포인터가 자식클래스를 가리킨다.

Parent *pp = &cp // cp는 자식 클래스 객체

  • 자식 클래스는 부모 클래스로 부터 상속을 받으니 부모 클래스의 생성자를 불러와 올바르게 타입을 만들어 낼 수 있다.

  • 하지만 부모 클래스형 포인트이기에 부모 클래스 정보밖에 없다.

    • 그냥 자식이 가지고 있는 부모의 정보를 가리킨다.
    • 따라서 자식 클래스만 가지고 있는 기능들을 사용할 수 없다.



다운 캐스팅

업 캐스팅과 반대로 부모 클래스는 자식의 정보를 가지지 않는데 없는 정보를 가리키는 포인터를 생성해서다.

  • Children *pc = &pp은 오류가 난다. // pp는 부모 클래스 객체
  • 자식 클래스의 생성자를 어떻게 호출할껀데? 제대로된 포인터 생성이 이루어지지 않는다.


  • 물론 어떻게 자식클래스를 부모클래스에 넣고 그 클래스를 다시 자식에게 넣고 강제적으로 다운 캐스팅하면 되긴하는데 컴파일해도 프로그램이 멈출 수 있다.
  • 그런데 이 오류를 컴파일러가 잡아내기 어려워서 하면 안되는 작업이다.



C언어 캐스팅

  • C언어의 캐스팅에 암시적 그리고 명시적 캐스팅이 있다
  • 컴파일러가 알아서 하는 암시적 캐스팅, 우리가 직접하는 명시적 캐스팅


그런데 명시적 캐스팅에서 몇가지 문제점이 있다.

  1. 적절하지 않은 방식으로 캐스팅을 해도 컴파일 오류가 발생하지 않는다.
  2. 가독성이 떨어진다.
  3. 캐스팅의 의미를 파악하기가 힘들다.
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로 구성된 자료형에 들어가면 데이터가 그대로 유지



참고


개인 공부 기록용 블로그입니다.
틀린 부분 있으다면 지적해주시면 감사하겠습니다!!

카테고리:

업데이트:

댓글남기기