'dynamic_cast'에 해당되는 글 2건

  1. 2012.10.31 dynamic_cast : Polymorphic 클래스 기반의 형 변환
  2. 2012.10.31 C++ 에서의 형 변환 연산

# 상속관계에 놓여있는 두 클래스 사이에서, 유도 클래스의 포인터 및 참조형 데이터를 기초 클래스의 포인터 및 참조형 데이터로 형 변환할 경우에는 dynamic_cast 연산자를 사용한다.


# 상속관계에 놓여있는 두 클래스 사이에서, 기초 클래스의 포인터 및 참조형 데이터를 유도 클래스의 포인터 및 참조형 데이터로 형 변환할 경우에는 static_cast 연산자를 사용한다.



하지만, 다음의 조건만 만족하면!! dynamic_cast 연산자도 기초 클래스의 포인터 및 참조형 데이터를 유도 클래스의 포인터 및 참조형으로의 형 변환을 허용한다.


"기초 클래스가 'Polymorphic Class' 이다."



Polymorphic 클래스란, 하나 이상의 가상함수를 지니는 클래스를 뜻한다. 그러니 상속관계에 놓여있는 두 클래스 사이에서 기초 클래스에 가상함수가 하나 이상 존재하면, dynamic_cast 연산자를 이용해서 기초 클래스의 포인터 및 참조형 데이터를 유도 클래스의 포인터 및 참조형 데이터로 변환이 가능하다.


 

13행: Simple 클래스가 Polymorphic 클래스이므로 Complex 클래스도 Polymorphic 클래스이다.

24행: 포인터 변수가 가리키는 것은 Complex 객체이다.

25행: 기초 클래스인 Simple이 Polymorphic 클래스이므로 dynamic_cast 연산자로 형 변환이 가능하다.


위의 main함수에서 dynamic_cast 연산이 성공한 이유는?


-> 포인터 변수 simPtr이 실제 가리키는 객체가 Complex 객체이기 때문이다. 즉, 포인터 변수 simPtr이 가리키는 객체를 Complex 형 포인터 변수 comPtr이 함께 가리켜도 문제되지 않기 때문에 성공한 것이다.



만약, 안정적이지 못한 형 변환을 시도할 경우, dynamic_cast는 NULL 포인터가 반환된다.



이렇듯 dynamic_cast는 안정적인 형 변환을 보장한다. 특히 컴파일 시간이 아닌 실행 시간에(프로그램이 실행중이 동안에) 안전성을 검사하도록 컴파일러가 바이너리 코드를 생성한다는 점에 주목할 필요가 있다. 

물론 이로 인해서 실행속도는 늦어지지만, 그만큼 안정적인 형 변환이 가능한 것이다. 그리고 이러한 특성 때문에 연산자의 이름이 dynamic으로 시작하는 것이다.


static_cast는 안전성을 보장하지 않는다. 컴파일러는 무조건 형 변환이 되도록 바이너리 코드를 생성하기 때문에, 그로 인한 실행의 결과는 전적으로 프로그래머가 책임져야 한다. 그래서 이러한 특정 때문에(실행중인 동안에 안전성 검사를 진행하지 않는 특성때문에) 연산자의 이름이 static으로 시작하는 것이다. 

물론, 실행속도는 빠르다. 실행 시간에 안전성 검사를 별도로 진행하지 않기 때문이다. 






bad_cast 예외


- 프로그래머가 정의하지 않아도 발생하는 예외.

bad_cast 예외는 dynamic_cast 연산자를 이용한 형 변환의 과정에서 발생할 수 있는 예외이다.




29행: 참조자 ref가 실제 참조하는 대상이 Simple 객체이기 때문에 Complex 참조형으로의 형 변환은 안전하지 못하다. 그리고 참조자를 대상으로는 NULL을 반환할 수 없기 때문에 이러한 상황에서는 bad_cast 예외가 발생한다.


※ 위 예제에서 보이듯이, 참조형을 대상으로 dynamic_cast 연산을 진행할 경우에는 bad_cast 예외가 발생할 수 있기 때문에 반드시 이에 대한 예외처리를 해야 한다.


Posted by scii
:

C++ 에서 C 스타일의 형 변환 연산자를 가리켜 '오래된 C 스타일 형 변환 연산자(Old C-style cast operator)' 라 부른다. 이렇듯 C 스타일의 형 변환 연산자는 C언어와의 호환성을 위해서 존재할 뿐, C++에서는 새로운 형 변화 연산자와 규칙을 제공하고 있다 .



40행: 문제가 없어 보이기도 하다. 하지만 기초 클래스의 포인터 형을 유도 클래스의 포인터 형으로 형 변환하는 것은  일반적인 경우의 형 변환이 아니다. 


이 예제의 문제점은 40행에 있다. 이것이 실수인지 아니면 일부러 이렇게 했는지 그 의도를 모르기 판단하기 힘들기 때문이다. 


그래서 이러하 유형으 논란과 문제점 때문에 C++ 에서는 다음과 같이 총 4개의 연산자를 추가로 제공하면서 용도에 맞는 형 변환 연산자의 사용을 유도하고 있다. 


static_cast

const_cast

dynamic_cast

reinterpret_cast


위의 형 변환 연산자들을 사용하면 프로그래머는 자신이 의도한 바를 명확히 표시할 수 있다. 따라서 컴파일러도 프로그래머의 실수를 지적해 줄 수 있고, 코드를 직접 작성하지 않은 프로그래머들도 코드를 직접 작성한 프로그래머의 실수여부를 판단할 수 있다. 







dynamic_cast : 상속관계에서의 안전한 형 변


dynamic_cast<T>(expr)

즉, <> 사이에 변환하고자 하는 자료형의 이름을 두되, 객체의 포인터 또는 참조형이 와야 하며, () 사이에는 변환의 대상이 와야 한다. 


※ dynamic_cast 연산자를 사용하겠다는 것은 다음의 의미가 담겨있다.

- 상속관계에 있는 유도 클래스의 포인터 및 참조형 데이터를 기초 클래스의 포인터 및 참조형 데이터로 형 변환하겠습니다.




※ 43행의 형 변환은 의도적으로라도 하면 안된다. 그러나 40행 같은 경우에는 경우에 따라서 필요할 것도 같다. 이러한 경우엔 어떻게 해야 하나?

- 이러한 형 변환을 의도적으로 진행한다는 것을 명시하기 위하 형 변환 연산자를 사용해야 한다.  그리고 그에 맞는 형 변환 연산자가 바로 static_cast 연산자이다.







static_cast : A타입에서 B타입으로


static_cast<T>(expn)

이것은, 유도 클래스의 포인터 및 참조형 데이터를 기초 클래스의 포인터 및 참조형 데이터로뿐만 아니라, 기초 클래스의 포인터 및 참조형 데이터도 유도 클래스의 포인터 및 참조형 데이터로 아무런 조건 없이 형 변환시켜 준다.

하지만 그데 대한 책임은 프로그래머에게 있다. 

 



43행 같은 경우에는 어떻게 해서든 정당화될 수 없는 상황이다. 따라서 이러한 형태로 문장을 구성하면 안된다. 하지만 static_cast는 dynamic_cast와 달리 이것 또한 허용한다. 


즉, static_cast 연산자는 dynamic_cast 연산자와 달리, 보다 많은 형 변환을 허용한다. 하지만 그에 따른 책임도 프로그래머가 져야 하기 때문에 신중하게 선택해야 한다. 

dynamic_cast 연산자를 사용할 수 있는 경우에는 dynamic_cast 연산자를 사용해서 안전성을 높여야 하며, 그 이외의 경우에는 정말 책임질 수 있는 상황에서만 제한적으로 static_cast 연산자를 사용해야 한다. 


※ 보다 빠른 static_cast 연산자

- dynamic_cast 연산자보다 static_cast 연산자를 사용했을 때 연산의 속도가 더 빠르다. 따라서 이러한 이유로 dynamic_cast 연산자를 사용해도 되는 상황에서 조차 static_cast 연산자를 사용하는 경우도 적지 않다.



static_cast 연산자는 기본 자료형 데이터간의 형 변환에도 사용이 된다. 




static_cast 연산자는 '기본 자료형 간의 형 변환'과 '클래스의 상속관계에서의 형 변환'만 허용을 하지만, C언어의 형 변환 연산자는 다음과 같이 말도 안되는 형 변환도 허영하기 때문에 여전히 static_cast 연산자의 사용은 의미를 갖는다.



위에서 보인 형 변환은 static_cast 연산자로는 불가능한 형 변환이다. 즉, 여전히 static_cast 연산자는 C언어의 형 변환 연산자보다 적은 것을 허용하고 있으며, 이로 인해서 static_cast 연산자를 보는 순간 다음과 같이 판단할 수 있다.


"상속관계에 있는 클래스의 포인터 및 참조형 데이터의 형 변환인가? 아니면 기본 자료형 데이터의 형 변환인가?"







const_cast : const의 성향을 삭제하라.


C++에서는 포인터와 참조자의 const 성향을 제거하는 형 변환을 목적으로 다음의 형 변환 연산자를 제공하고 있다.

const_cast<T>(expn)



참조자, 포인터의 const 성향을 제거하는 것이 가치를 떨어뜨릴 수 있다. 허나, 다른 이면에선 나름의 의미를 발견할 수 있다. 위의 예제처럼.


이렇듯 const_cast 형 변환 연산은, 함수의 인자전달 시 const 선언으로 인한 형의 불일치가 발생해서 인자의 전달이 불가능한 경우에 유용하게 사용이 된다. 


※ 위 예제에서 보이는 것과 같이 const_cast 연산자의 긍정적인 측면이 잘 드러나는 경우에만 제한적으로 사용해야 한다.

const_cast 연산자는 volatile(컴파일러의 최적화를 제한하는 목적) 의 성향을 제거하는데도 사용할 수 있다.







reinterpret_cast : 상관없는 자료형으로의 형 변환


reinterpret_cast 연산자는 전혀 상관이 없는 자료형으로의 형 변환에 사용이 되며, 기본적인 형태는 다음과 같다.

reinterpret_cast<T>(expn)


reinterpret_cast 연산자는 포인터를 대상으로 하는, 그리고 포인터와 관련이 있는 모든 유형의 형 변환을 허용한다.



7행: int 형 정수에 바이트 단위 접근을 위해서 int형 포인터를 char형 포인터로 형 변환하고 있다.

10행: 바이트 단위 데이터를 문자가 아닌 정수의 형태로 출력하기 위해서 char형 데이터를 int형으로 변환하고 있다.



reinterpret_cast 연산자는 포인터와 관련이 있는 모든 유형의 형 변환을 허용한다고 했다. 

따라서 다음과 같은 문장의 구성도 가능하다.



위 예제의 경우에 크게 의미를 부여하기 어렵지만, 특정 상황에서는 이러한 유형의 연산이 유용하게 사용되기도 하며, 이는 reinterpret_cast 연산자가 포인터와 관련이 있는 모든 유형의 형 변환을 허용한다는 사실을 뒷받침하기도 한다.


Posted by scii
: