2011-01-03 1 views
23

C++에서 객체의 실제 유형이 동일한 클래스가 아닌 동일한 클래스 또는 파생 클래스가 아닌지 알고 싶습니다. 이것은 다음 C# 코드와 유사합니다.C++에서 유형 검사

Class Base 
{ 
} 

Class Child:Base 
{ 
} 

Base childObject = new Child(); 

If (childObject.GetType() == typeof(Child)) 
{ 
// do some code 
} 

고마워요!

+0

'childObject' 유형은 무엇입니까? 런타임시에 타입의 개념이 존재하지 않기 때문에 C++에서 이것을 수행하는 일반적인 방법은 없습니다. –

+0

자, 질문을 편집하겠다. – Homam

+2

childObject.GetType()이 무엇인지에 대해서는 언급하지 않았지만 그럼에도 불구하고이 코드는 타입 비교에서 분기하기 때문에 끔찍한 코드이다. 그것이 OOP가 제거해야하는 것입니다. –

답변

48

두 가지 방법으로이 작업을 수행 할 수 있습니다. 먼저 typeid 연산자를 사용할 수 있습니다.이 연산자는 객체 유형에 대한 정보가 들어있는 type_info 구조체를 반환합니다. 당신이 typeid(*ptr)를 사용할 필요가 여기에 있지 typeid(ptr)

Base* ptr = /* ... */ 
if (typeid(*ptr) == typeid(DerivedType)) { 
    /* ... ptr points to a DerivedType ... */ 
} 

공지 예를 ​​들면 다음과 같습니다. typeid(ptr)을 사용하는 경우 Base*에 대한 포인터는 Base*이므로 포인터는 Base*type_info 개체를 반환합니다.

주목할 점은 ptr이 정확히 이고DerivedType으로 표시되는지 확인하는 것입니다. ptrDerivedType (아마도 EvenMoreDerivedType)에서 파생 된 유형의 객체를 가리키는 경우이 코드는 올바르게 작동하지 않습니다.

좀 더 견고한 유형의 개체를 가리키는 지 확인하는 다른 방법은 dynamic_cast 연산자를 사용하는 것입니다. dynamic_cast은 런타임시 검사 된 유형 변환을 수행하여 유형 변환이 성공하면 유효한 포인터를 생성하고 그렇지 않으면 NULL을 리턴합니다. 예를 들면 :

이는 EvenMoreDerivedType 같은에서 ptr 경우 점, 캐스트는 여전히 EvenMoreDerivedType 상속 때문에 DerivedType에서 성공하는 추가 장점이있다
Base* ptr = /* ... */; 
DerivedType* derived = dynamic_cast<DerivedType*>(ptr); 
if (derived) { 
    /* ... points to a DerivedType ... */ 
} 

.

최종 생각으로, 당신은 종종 다음과 같은 코드를 참조하십시오

Base* ptr = /* ... */ 
if (DerivedType* derived = dynamic_cast<DerivedType*>(ptr)) { 
    /* ... points to a DerivedType ... */ 
} 

이는 if 문의 본체에 derived 포인터를 로컬 스코프와 제로가 아닌 값이 C++로 true로 평가한다는 사실을 사용합니다. 필자는 개인적으로 읽기 쉽고 오류가 발생하기 쉽지만, 가장 쉬운 방법은 사용자에게 쉽습니다.

희망이 도움이됩니다.

+0

그는 파생 된 클래스가 아니라 객체가 Base인지 여부를 알고 싶어합니다. – Puppy

+0

아 ... 포인터가 자식 형식을 가리키는 지 확인하는 예제 코드로 인해 혼란스러워합니다. 유효한 포인트. – templatetypedef

2

typeid()를 사용할 수 있습니다.

if (typeid(childObject) == typeid(ChildType)) { 
} 

이 값이 참이면 자식 클래스라는 것을 알게됩니다.

+2

런타임 유형 식별 (RTTI)을 사용하여 컴파일해야합니다. –

+3

비교되는 항목에 vtbl이있는 경우에만 **이 기능이 ** 작동합니다. –

+0

@Billy : 사실입니다.하지만 누가 기본 클래스에 가상 소멸자를 제공하지 않습니까? 가상 함수는 사실상 상속의 포인트입니다. 그것을 기대하는 것은 무리가 아닙니다. – Puppy

9

DeadMG의 대답은 정확하지만 (나는 여러 번 typeid를 사용했습니다), 나는 이것을 후세에 던질 것이라고 생각했습니다. 객체 지향 뷰에서이를 수행하는 "올바른"방법은 다음과 같습니다.

Class Base 
{ 
    virtual void something() { 
     // probably a no-op, but maybe some default stuff 
    } 
} 

Class Child : public Base 
{ 
    virtual void something() { 
     // do your child-specific code here 
    } 
} 

Base* childObject = new Child(); 
childObject->something(); // does the right thing 
+0

나는이 대답을 초. DeadMG의 대답은 올바른 프로그래밍 연습이 아니지만 ...! –

+0

이것은 개체 내부에 뭔가를하고 싶을 때 잘 작동합니다. 반면에 유형에 따라 객체를 처리하려는 경우 복잡하고 불편 해집니다 (모든 이중 디스패치 및 방문자의 경우) –

+0

@ 7vies, true이지만 가장 일반적으로이 가상 메서드 접근 방식이 가장 효과적 일 수 있습니다. 유지 관리가 가장 쉽다. dynamic_cast 또는 typeid가 올바른 접근 방법 인 경우가 있지만 그보다 드문 경우입니다. – Tim