[C++] C++의 형변환
알고리즘 문제 풀이를 할 때 내가 의도한대로 형변환이 되지 않고 어디까지 형변환이 되고 있는건지 이해가 잘 가지 않았다.
C++ 형변환에 대한 이해가 부족하다고 느껴져서 간단하게 정리하였다. C++ 의 상속 전반에 대한 공부가 부족하여 완전히 이해하지는 못하였다. (씹어먹는 C++에서 상속을 건너뛰었더니 이런 불상사가.. )
C 스타일 형변환 (오래된 형변환)
C에서는 아래와 같은 방법으로 형변환을 할 수 있었다.
int n = 3;
float n1 = (float)n;
float n2 = float(n);
위와 같이 형변환하는 방식을 C++에서 C 스타일 형변환
또는 오래된 형변환
이라고 한다. 이렇게 형변환이 구분되어 있다는 것은 C++에서 형변환하는 방법이 따로 존재한다는 뜻일거다.
C++이 제공하는 형변환
C++에서는 무려 네 가지의 형변환 방법을 제공하고 있다.
- static_cast
- dynamic_cast
- reinterpret_cast
- const_cast
예를 들면 아래와 같이 형변환을 할 수 있다.
double d = 3.14;
int num = static_cast<int>(d);
구체적으로 각 case를 살펴보자.
static_cast
static(정적)이라는 이름에서 알 수 있듯이 static_cast는 컴파일 단계에서 형변환이 가능한지 컴파일러가 체크할 수 있다. C++에 정의된 기본 자료형간의 형변환에서 사용된다. (밑에 언급할 dynamic_cast는 사용자가 정의한 클래스 간의 형변환 가능)
double d = 3.14;
int n1 = static_cast<int>(d);
int n2 = dynamic_cast<int>(d); // 컴파일 에러, 기본 자료형 형변환은 불가
다시 말해서 기본 자료형에 대해서는 사용할 수 있는 선택자가 static_cast
로 정해져있다는 것이다. static_cast와 dynamic_cast 중에서 어떤 것을 사용할지는 부모-자식 클래스 간의 포인터/참조 형식의 형변환
의 경우에서만 고민하면 된다.
static_cast의 경우에는
부모 클래스의 참조/포인터 형식 -> 자식 클래스의 참조/포인터 (O)
자식 클래스의 참조/포인터 -> 부모 클래스의 참조/포인터 형식 (O)
위와 같은 형변환을 허용한다.
말로만 보면 이해가 안가니 코드를 살펴보자.
#include <iostream>
#include <string>
class Human{
int age;
public:
Human(int age) : age(age) {}
void showInfo() {
std::cout << "내 나이는 " << age << "입니다" << std::endl;
}
};
class Man : public Human {
std::string gender;
public:
Man(int age, std::string gender) : Human(age), gender(gender) {}
void showInfo() {
Human::showInfo();
std::cout << "내 성별은 " << gender << "입니다" << std::endl;
}
};
Human과 Man 클래스를 정의하였다. Man은 Human을 상속 후 추가로 gender 변수를 가지고 있고 showInfo도 오버라이딩 하였다. static_cast를 통해 두 클래스의 형변환을 할 수 있다.
int main() {
Human* human1 = new Man(20, "남자");
Man* man1 = static_cast<Man*>(human1);
man1->showInfo();
Human* human2 = new Human(30);
Man* man2 = static_cast<Man*>(human2);
man2->showInfo();
return 0;
}
내 나이는 20입니다
내 성별은 남자입니다
내 나이는 30입니다
내 성별은 입니다
정상적으로 컴파일이 되고 출력 결과는 위와 같다. 그런데 첫 번째 케이스의 형 변환은 이해가 되는데, 아래 케이스는 결과만 봐도 뭔가 이상하지 않은가? static_cast는 상속관계에서의 형변환이 가능은 하지만 위와 같이 안전한 형변환이라고 하기에는 무리가 있다.
dynamic_cast
dynamic_cast는 static_cast와 달리 컴파일 단계가 아닌 런타임 단계에서 안정성 검사를 진행한다.
(기초적인 알고리즘 풀이에서도 static_cast 외에 다른 것들이 사용될라나..? )
어쨌든 dynamic_cast는 자식 클래스의 참조/포인터 형식 -> 부모 클래스의 참조/포인터 형식으로의 형변환을 허용한다.
reinterpret_cast
위 내용은 생략한다.. 간단하게 언급하면 포인터/참조 타입에 상관없이 무조건 강제적인 형변환을 해야할 때 사용하는 것이다.
const_cast
const_cast는 const 성질을 제거하기 위해 사용하는 연산자이다.
const std::string str1 = "hello";
std::string str2 = const_cast<std::string>(str2);
std::cout << str2;
const가 아닌 변수를 매개변수로 받는 것으로 정의된 함수에 const형을 전달하지 못하기 때문에 이때 const_cast를 사용할 수 있다.