RTTI

프로그래밍/C, C++ 2015. 3. 31. 07:07


RTTI (runtime type information)RTTI는 C++ 컴파일러 내에 포함되어 있는 기능으로서, 객체의 유형을 실행 시에 결정할 수 있도록 허용한다. C++이나 다른 고급언어의 컴파일러에서 가지고 있는 이 기능은, 메모리 상주 객체에 유형 정보를 추가한다. 이렇게 함으로써, 실행 시스템은 객체의 캐스트가 유효한 것인지를 확실히 하기 위해, 그 객체가 특정 유형인지를 결정할 수 있다. 객체 기술의 기본 원리 중 하나가, 실행시 객체를 동적으로 변화시킬 수 있는 능력인 polymorphism이다. 


 

RTTI 의 목적

 

하나의 공통 기초 클래스로부터 상속된 클래스 계층 존재 가정.
이 클래스 계층에 속해 있는 클래스들의 어떤 객체를 기초 클래스 포인터가 지시하도록 설정 가능. 어떤 정보를 처리한 후 이들 클래스들 중에서 어느 하나를 선택하고,
그 클래스형의 한 객체를 생성하고, 기초 클래스 포인터에 대입하기 위해 그 객체의 주소를 리턴하는 함수를 호출.
그 포인터가 지시하는 객체의 종류가 무엇인지 어떻게 알 수 있을까?

어떤 클래스 메서드의 정확한 버전을 호출하고 싶기 때문에 데이터형을 알고 싶을 수도 있음.
그러한 경우 그 함수가 클래스 계층의 모든 멤버들에 의해 처리되는 가상 함수라면, 굳이 그 객체형을 알 필요는 없음. 그러나 파생 객체가 상속되지 않은 메서드를 가지고 있을 수도 있고, 일부 객체들만이 그 메서드를 사용할 수도 있음. 또는 디버깅 목적으로, 어떤 종류의 객체들이 생성되는지 추적하고 싶을 수도 있음.

 

1. dynamic_cast 연산자는, 가장 많이 사용.
포인터가 지시하는 객체형이 무엇인지 알려 주지 않음. 대신 그 객체의 주소를 특정형의 포인터에 안전하게 대입할 수 있는지 알려 줌.

가능하다면, 기초 클래스형을 지시하는 포인터로부터 파생 클래스형을 지시하는 포인터를 생성. 반면에 가능하지 않다면, 널 포인터인 0을 리턴.


2. typeid 연산자는,
두 객체의 데이터형이 같은지 결정 가능.
어떤 객체의 정확히 데이터형을 식별하는 하나의 값을 리턴.

- 클래스의 이름
- 객체로 평가되는 식

typeid 연산자는 type_info 객체에 대한 참조를 리턴.

 

3. type_info 구조체는,
어떤 특별한 데이터형에 대한 정보를 저장.

typeinfo(이전의 typeinfo.h) 헤더 파일에 정의되어 있는 클래스.
이 클래스는 데이터혀을 비교하는데 사용할 수 있도록 == 와 != 연산자 오버로딩.

ex.
typeid(Magnificent) == typeid(*pg)

pg가 널 포인터이면, bad_typeid 예외 발생

 

 

* RTTI 는 가상 함수들을 가지고 있는 클래스들에 대해서만 사용 가능.
  그들이 파생 객체들의 주소를 기초 클래스 포인터들에 대입해야 하는 유일한 클래스 계층 때문.

 

우선, 설사 typeid로 dynamic_cast가 할 수 있는 모든 걸 할 수 있다고 해도, 반대로 typeid가 할 수 있는건 dynamic_cast로도 할 수 있기 때문에 dynamic_cast를 어따쓰냐는 질문은 'dynamic_cast를 쓰면 typeid를 쓸 필요가 없죠. 그럼 typeid는 뭐에쓰나요?' 라는 질문과 가치가 같습니다.
한쪽으로 다른 쪽을 할 수 있다고 해서 다른 쪽이 쓸모 없어지는 건 아닙니다. 더 편리한 방법이 있다면 그걸 쓸 수도 있겠죠.
typeid로 일일이 타입을 체크한 후에 static_cast로 캐스팅하는 것보다는 dynamic_cast로 캐스팅하는게 훨씬 깔끔하고 직관적일 수 있습니다.
memcpy가 있는데 왜 strcpy를 쓸까요? strcpy가 있는데 왜 strdup를 쓸까요? 생각해보시기 바랍니다.
더 나아가 typeid로 체크하고 static_cast로 캐스팅하게 되면 같은 변수/타입을 여러번 적어줘야하는데(bp의 typeid를 비교한 후에 bp에 대입), 같은 내용을 중복 적재하다보면 실수할 확률도 높아지죠. 예를 들면 foo()안에서 if 조건안의 대입문이 뒤바뀌는 실수를 할 수도 있습니다(bp의 typeid를 비교한 후에 cp에 대입하는 실수).



A - B, A - C 가 아니라 A - B - C 라고 합시다.
그리고 원하는 바가 B 객체이거나 B 의 파생객체인지 확인하기 위해서 typeid 를 쓰고자 하신다면 B, C 둘 다 확인해봐야 합니다.
만일 상속구조가 늘어나면 비교대상은 계속해서 늘어나게 됩니다.
dynamic_cast 를 쓴다면 B 로 casting 한번만 해보면 됩니다. dynamic_cast 는 객체의 부모 class 를 따라가면서 확인하는 과정을 거칩니다.
즉 객체의 class 가 C 였다면 C - B - A 순서로 올라가면서 casting 이 가능한지 조사해봅니다. 이 경우는 B 에서 멈추겠죠.
그래서 dynamic_cast 는 매우 느려질 수 있습니다.
typeid 로 가능한 요구사항 즉 단순히 정확한 비교 하나를 원하시는 거라면 typeid 쓰시는게 좋죠. 그리고 그 후 casting 이 필요하다면 static_cast 를 쓰는 것은 상당히 바람직합니다.
그러나 dynamic_cast 를 쓴다고 그리 느려지는 것도 아닐 겁니다. Compiler 구현을 그리 멍청하게 하지는 않았을테니까요.
다만 초기 Visual C++ 의 dynamic_cast 는 매우 느렸다고 하더군요. RTTI 기능을 끌 수 있게 한 이유 중 하나였을 겁니다.


- 내용 출처

soen.kr

https://kldp.org/node/141614

http://softwareji.tistory.com/107



Posted by GENESIS8

댓글을 달아 주세요

  1. ㅇㅇ 2021.05.23 06:08  댓글주소  수정/삭제  댓글쓰기

    dynamic_cast를 쓰면 typeid는 안써도 되는거죠?