타입 변환

Oak_Cassia·2021년 11월 15일
0

타입을 변환을 분류해보자.

비트열 재구성에 따라

int a= 100;
float b =(float)a; 

int 를 float 타입으로 변환할 때
2의 보수 형식에서
부동소수점 형식으로 변환이 된다.

100(0x64)이 저장되어 있지 않다.
부동소수점 형식의 100(근삿값)으로 변환되어 저장되어 있다.



	int a = 100;
	float b = (float&)a;
	int a = 100;
	float* b = (float*)a;

위 두 방식으로 했을 때는

100이 저장되어 있다.


안전도에 따라

안전한 변환
의미가 항상 일치하는 경우를 말한다.
같은 타입이면서 크기만 더 큰 타입으로 업 캐스팅

  • (char -> short )
  • (int-> int64)
    등등

불안전한 경우
의미가 100%일치한다고 보장하지 못 하는 경우.
타입이 다르거나 타입의 크기가 작아지는 경우

  • (int -> float)
  • (int -> short)

프로그래머의 의도에 따라

암시적
이미 알려진 타입 변환 규칙에 따라 컴파일러가 자동으로 변환

int a=123;
float b = a;

명시적

int a =1234;
int* b= (int*) a

연관성에 따라

연관없는 클래스 사이의 그냥 타입 변환

Person p1;
dog d1=(dog)p1; (빨간 줄)

빨간 줄을 없애려면 클래스에 타입 변환 생성자를 만들면 된다.
해당 클래스 타입을 상수형 참조자로 받는 생성자를 만들자

Person(const Dog& dog);

int main()
{
	Dog d1;
	Person p1 = d1;//가능!
}

타입변환 연산자도 가능하다. 반환형과 매개변수가 없다.

class Person
{
	int hands;
...

public:
	operator Dog()
	{
              Dog dog;
              dog.tail=hands//dog의 멤버변수를 채워준다. 객체의 것으로
              return dog
	}
 };
int main()
{
	Dog d1;
	Person p1 = d1;
	Dog d2 = p1;
} 

객체 값을 받는 생성자나 연산자를 만들어야 한다.


연관없는 클래스 사이의 참조 타입 변환

Person p(1);
Dog& d = (Dog&)p;//d의 타입을 Dog로 해도 된다.

어셈블리 관점에서 포인터나 참조나 같다.
void* 처럼 포인터 형은 타입변환이 (뭔가) 자유롭다.


상속관계에서 타입 변환
자식 클래스에서 부모 클래스가능
부모 클래스에서 자식 클래스불가능


상속관계클래스의 참조타입 변환
부모-> 자식 명시적으로 가능
Poodle p2 = (Poodle&)dog2; //() 타입연산자 사용하면 가능
자식-> 부모는 그냥 가능
Dog& d3 = poodle1;


값타입 변환 : 비트열을 바꾸는 것 같이 논리적으로 말이되게 바꾸는 변환만 가능

참조 타입변환은 보는 관점만 바꾸는 변환
명시적으로 요구하면 해준다.


포인터로 타입 변환

명시적으로 할 경우 연관성이 없는 클래스 사이의 포인터 변환이 가능하다.
객체사이의 크기가 다를 경우 문제가 생긴다.

할당된 메모리를 넘어서 접근할 수 있기 때문에 위험

상속관계 포인터 타입 변환

부모 -> 자식 명시적으로 하면 가능하다.( 잘못된 접근을 할 수도 있다.)

자식 -> 부모암시적으로도 가능하다.

예)
자식으로 생성 (부모 생성자와 자식 생성자 호출)
부모로 메모리 해제 (부모 소멸자만 호출)
소멸자에도 virtual을 붙여주면 (자식, 부모 소멸자 호출)

부모클래스에 소멸자에 virtual을 붙이자 나중에 스마트 포인터 같이 생성자와 소멸자에서 메모리 할당 해제를 할 경우 중요!


그럼 암시적으로만 하면 안전하지 않을까?

하지만 명시적인 방법을 사용해야할 때가 있다.
작은 범주들을 아우르는 융통성을 보여야할 때 부모클래스 포인터 사용하면 편리하다.

c++ 4가지 캐스팅

a = static_cast<int>(b); 이런 형태

dynamic_cast

  • 상속관계에서의 안전한 형변환
    • 상속관계에 놓인 두 클래스 사이에서 자식 클래스의 포인터 및 참조형 데이터를 부모클래스의 것으로 변환하는 경우.
    • 부모클래스 포인터지만 동적할당으로 자식 클래스의 객체로 생성했을 때(실제로 가리키는 객체가 자식 클래스의 객체일 때) 부모-> 자식 변환
  • 컴파일 시간이 아닌 실행 시간에 안전성을 검사하도록 컴파일러가 바이너리 코드(목적 파일)를 생성한다.
  • RTTI(runtime type information)
    -형변환 하려는 클래스는 가상함수가 있어야 한다.(가상함수 테이블 이용?)
    -잘못된 타입으로 캐스팅 하면 nullptr 반환한다.

static_cast

  • 부모 -> 자식 (포인터 or 참조자)
  • 자식 -> 부모 (포인터 or 참조자)
  • 기본 자료형 간의 변환 (int -> float)
  • 개발자가 책임져야 한다.
  • dynamic_cast 보다 빠르다.

const_cast

  • 포인터와 첨조자의 const를 없애거나 붙이는 형변환
  • 함수의 인자 전달 시 const 선언으로 타입이 다를 때 사용
  • volatile 제거

reinterpret_cast

  • 상관없는 자료형으로 변환
  • 포인터를 대상으로 하는, 포인터와 관련 있는 모든 유형의 형 변환

bad_cast exeption

참조자를 대상으로 dynamic_cast 연산자를 이용한 형 변환의 과정에서 발생할 수 있는 예외.(참조자는 NULL을 반환하지 못하기 때문에 발생)

profile
rust로 뭐할까

0개의 댓글