강께르의 개발일지

[C++] C++의 형 변환 연산자 본문

프로그래밍/C++

[C++] C++의 형 변환 연산자

강께르 2021. 6. 28. 23:12

1. C의 형 변환

int num = 10;
std::cout << (double)num;

- 다음과 같은 형 변환을 C 스타일의 형 변환이라고 한다.

- C에서의 형 변환은 명시적으로 특정 자료형으로 변환해주는 연산자이다. 바꾸지 못하는 자료형이 없을 정도로 강력하다.

- 그만큼 강제적으로 형 변환을 시켜주기 때문에 프로그래머가 형 변환을 실수해도 컴파일러가 이를 잡아내지 못하는 경우가 있다.

 

- 이에 대한 문제점을 정리하자면 다음과 같다.

- C 스타일의 형 변환은 눈에 잘 띄지 않아서 찾기 힘들다. 단순히 괄호만 씌우는 모양이 함수의 매개변수처럼 보이기도 하며, 유의 깊게 찾으려 하지 않는 이상 지나치기가 쉽다.

- 명시적인 형 변환을 수행하였다는 것은 암시적 형 변환을 허용하지 않겠다는 것이다. 암시적 형 변환은 범위가 상대적으로 작은 변수가 큰 변수와의 연산 따위가 있을 경우, 작은 변수를 큰 변수의 자료형으로 변환되는 것을 이야기한다.

- 이는 컴파일러가 알아서 신경써주는 부분인데 만약 명시적 형 변환을 걸어버린다면 컴파일러가 암시적 형 변환을 할 수 없게 막아버린다는 것이다.

- C 스타일의 형 변환은 형 변환의 의도를 구별하기 힘들다고 한다. 이 의미는 C++의 연산자를 조사하면서 알게 될 것 같다.

 

- 위와 같은 문제점으로 인해 C++은 다양한 형 변환 연산자를 제공하고 있다.

- 아래에 볼 연산자는 다음과 같은 공통점을 가지고 있다.

- <>에 사이에는 자료형이 들어갈 것이다. 그리고 expr은 형 변환하고자하는 변수나 그 이외의 것이 들어갈 것이다.

- 요구한 형 변환이 적절한지 판단한다. 적절한 경우라면 형 변환된 데이터를 반환하지만, 그렇지 않다면 에러를 발생하게 된다.

 

2. static_cast

static_cast <T> (expr)

- static_cast는 정적 캐스트 연산자라고 한다. 형 변환을 하게 되면 컴파일 타임에 형 변환이 가능한지 검사한다.

- 컴파일 타임에 형 변환이 가능한지 검사하는 점이 유용한 이유는 다음을 예로 설명하고자 한다.

 

- 만약 double로 선언한 변수가 있다고 하자. 이 double 변수를 C 스타일을 이용해 int형 포인터로 형 변환한다고 하자.

- 프로그래머의 실수인지는 모르겠지만, double 변수를 포인터 변수로 바꾼다는 것은 원하는 결과를 얻지 못할 것이다. 숫자 값과 주소 값은 그 쓰임새가 다르기 때문이다. C 스타일은 이러한 문제를 잡아내지 못하고 형 변환을 한다.

- 하지만 static_cast는 어떨까? 컴파일 타임 중에 이러한 형 변환이 적합한지 판단하여 에러를 발생할 것이다.

- 컴파일 타임에 에러를 발생한다는 것은 장점이다. 런타임 중에 발견하는 것이 아닌 조기에 발견해 조치할 수 있기 때문이다.

 

- 아래에 설명할 dynamic_cast와 차이를 보이는 점이 있다. static_cast는 사용자가 정의한 클래스가 아닌 C++ 내부에 정의된 기본 자료형에 대한 형 변환도 가능하다.

- dynamic_cast는 기본 자료형에 대한 형 변환이 불가능하다.

 

- 기본 자료형이 아닌 부모-자식 클래스 간의 포인터/참조 형식의 형 변환에서는 어떨까?

- static_cast는 다음과 같다고 할 수 있다.

 

부모 클래스의 참조/포인터 형식에서 자식 클래스의 참조/포인터 형식으로 형변환을 허용합니다. 그리고

자식 클래스의 참조/포인터 형식에서 부모 클래스의 참조/포인터 형식으로의 형변환도 허용합니다. 

 

부모 클래스의 참조/포인터 -> 자식 클래스의 참조/포인터

자식 클래스의 참조/포인터 -> 부모 클래스의 참조/포인터

 

- static_cast는 dynamic_cast보다 덜 엄격한 기준으로 형 변환을 지원한다. 그렇기에 만약 부모 클래스 객체를 가리키고 있는 부모 클래스의 포인터 변수를 형 변환을 해 자식 클래스 포인터로 바꾸었다면?

- 이를 에러라고 잡지는 않겠지만, 원하는 결과가 나오지 않을 수 있다. 이에 대한 책임은 설계한 프로그래머가 져야하는 것이다.

- 이런 경우의 에러를 검출하고 조치하고 싶다면 아래의 형 변환 연산자를 사용해야 할 것이다.

 

3. dynamic_cast

dynamic_cast <T> (expr)

- dynamic_cast는 상속 관계에서의 안전한 형 변환을 제공한다.

- static_cast는 컴파일 타임에 형 변환에 대한 검사를 하고 에러를 발생하지만, dynamic_cast는 런타임 중에 검사한다.

- dynamic_cast는 다음과 같다고 할 수 있다.

 

자식 클래스의 참조/포인터 형식에서 부모 클래스의 참조/포인터 형식으로 형변환을 허용합니다.

 

자식 클래스의 참조/포인터 -> 부모 클래스의 참조/포인터

 

- 아무래도 이런 점때문인 것 같다. 부모 클래스가 자식 클래스에 대해서 상속하는 입장이라 아는 것이 없기에 문제될 요인이 많지만, 자식 클래스는 부모 클래스에게 상속을 받는 입장이라 부모 클래스에 대해 알고 있는 것이 있기 때문에 부모 클래스의 자료형으로 따라가도 상관 없다는 것으로 이해된다. 자식 클래스를 마치 부모 클래스처럼 다룰 수 있다는 것이다.

- 이것이 이전에 배웠던 업캐스팅이 적용된 사례 중 하나라고 혼자만... 생각한다.

 

- 하지만 이런 경우는 어떨까? 부모 클래스 포인터로 자식 클래스를 동적할당한 객체의 주소값을 받는 것은 가능하다. 왜냐면 이 경우 업캐스팅이 적용되어 부모 클래스처럼 다룰 수 있기 때문이다.

- 하지만 그 포인터를 다시 dynamic_cast로 자식 클래스 포인터로 형 변환하려고 한다면 어떨까? 생각으로는 가능할 것 같은데 dynamic_cast의 특징인 부모 클래스 포인터를 자식 클래스 포인터로 형 변환을 허용하지 않아서 불가능하다.

- 그럼 생각으로만 유용할 것 같은 이 형 변환을 적용하지 못하는 것인가? dynamic_cast에게 예외적인 상황이 있다.

 

하나 이상의 가상함수를 가진 다형성 클래스에 한해서는

부모 클래스의 참조/포인터 형식에서 자식 클래스의 참조/포인터로 형변환을 허용합니다 

 

부모 클래스가 가상함수를 가지고 있다면

부모 클래스 참조/포인터 -> 자식 클래스의 참조/포인터

 

- 부모 클래스에게 가상함수가 있어 자식 클래스에서 가상 함수를 오버라이딩했다면 이는 형 변환이 가능하다고 한다.

 

4. reinterpret_cast

reinterpret_cast <T> (expr)

- reinterpret_cast는 포인터와 참조에 관련된 형 변환만 지원한다. 하지만 C 스타일처럼 형 변환에 있어서 무조건적인 변환을 수행한다.

- 그래서 클래스의 포인터를 기본 자료형 포인터로 변환해도 에러를 검출하지 않는다. 이런 연산자는 어떻게 사용할 수 있을까?

- 주소값에 대한 연산 등 많은 예들이 있지만 검색한 것 중에서 가장 알맞은 용도는 해당 주소가 가지고 있는 값을 어떤 형 변환을 해도 그대로 보존하고 있다는 것 같다.

- 형 변환을 하다보면 변환하고자 하는 자료형에 따라 가지고 있는 값이 달라질 수 있고, 원래 갖던 자료형으로 형 변환하여 돌아와도 그 값을 그대로 유지하지 못하는 경우가 있다.

- reinterpret_cast는 그 값을 보장한다는 장점이 있다. 하지만 강제적 형 변환이기에 자주 사용은 하지 않는다.

 

5. const_cast

const_cast <T> (expr)

- const_cast는 expr의 const, volatile을 제거할 때 사용한다. 하지만 const로 선언했다는 것은 그만한 의미를 담고 있기에 사용에는 유의해야 한다.

 

volatile 키워드 : 이 키워드로 선언한 변수는 컴파일러가 최적화 과정에서 변수를 상수 취급하는 작업을 하게될 때, 그 작업에서 이 변수를 열외한다는 의미이다. 최적화하는 과정이기에 프로그램의 성능을 높이려하는 것이지만 하드웨어와 관련된 변수라면 문제가 될 수 있기에 이 키워드를 사용한다고 한다.

출처 :

더보기

 

'프로그래밍 > C++' 카테고리의 다른 글

[C++] list 템플릿 클래스  (0) 2021.06.21
[C++] vector 템플릿 클래스  (0) 2021.06.18
[C++] STL에 대해  (0) 2021.06.18
[C++] 템플릿에 대해(클래스 템플릿)  (0) 2021.06.18
[C++] 템플릿에 대해(함수 템플릿)  (0) 2021.06.17