C++에는 객체가 특정 클래스 타입의 인스턴스인지 직접 판별할 수 있는 내장 연산자가 없습니다. 반면 Java에서는 instanceof 연산자를 통해 이러한 기능을 간편하게 사용할 수 있습니다.
C++11에서는 is_base_of<Base, T>라는 타입 트레이트가 도입되었습니다. 이는 컴파일 시점에 한 클래스가 다른 클래스의 기반(base) 클래스인지 여부를 검사하지만, 실제 객체 인스턴스가 해당 타입으로 변환 가능한지까지는 확인해 주지 않습니다.
Java의 instanceof와 가장 유사한 동작을 구현하려면 dynamic_cast<new-type>(expression)을 활용하는 것이 가장 좋은 방법입니다. dynamic_cast는 주어진 값을 지정된 타입으로 변환을 시도하고, 성공하면 변환된 포인터를 반환하며 실패하면 null 포인터를 반환합니다.
단, dynamic_cast가 정상적으로 동작하려면 다음 두 가지 조건을 충족해야 합니다.
- 대상 포인터가 다형적(polymorphic)이어야 합니다. 즉, 클래스에 최소 한 개 이상의 가상 함수(virtual function)가 정의되어 있어야 합니다.
- 컴파일러에서 RTTI(런타임 타입 정보, Runtime Type Information) 옵션이 활성화되어 있어야 합니다.
예제 코드
#include <iostream>
using namespace std;
template<typename Base, typename T>
inline bool instanceof(const T *ptr) {
return dynamic_cast<const Base*>(ptr) != nullptr;
}
class Parent {
public:
virtual ~Parent() {}
virtual void foo() { std::cout << "Parent\n"; }
};
class Child : public Parent {
public:
virtual void foo() { std::cout << "Child\n"; }
};
class AnotherClass {};
int main() {
Parent p;
Child c;
AnotherClass a;
Parent *ptr1 = &p;
Child *ptr2 = &c;
AnotherClass *ptr3 = &a;
if (instanceof<Parent>(ptr1)) {
cout << "p is an instance of the class Parent" << endl;
} else {
cout << "p is not an instance of the class Parent" << endl;
}
if (instanceof<Parent>(ptr2)) {
cout << "c is an instance of the class Parent" << endl;
} else {
cout << "c is not an instance of the class Parent" << endl;
}
if (instanceof<Child>(ptr2)) {
cout << "c is an instance of the class Child" << endl;
} else {
cout << "c is not an instance of the class Child" << endl;
}
if (instanceof<Child>(ptr1)) {
cout << "p is an instance of the class Child" << endl;
} else {
cout << "p is not an instance of the class Child" << endl;
}
if (instanceof<AnotherClass>(ptr2)) {
cout << "c is an instance of AnotherClass class" << endl;
} else {
cout << "c is not an instance of AnotherClass class" << endl;
}
}
실행 결과
p is an instance of the class Parent c is an instance of the class Parent c is an instance of the class Child p is not an instance of the class Child c is not an instance of AnotherClass class
결과 분석
- p는 Parent 타입의 객체이므로 Parent의 인스턴스로 판별됩니다.
- c는 Child 타입이지만 Parent를 상속받고 있으므로, 업캐스트가 가능해 Parent의 인스턴스로도 판별됩니다.
- c는 당연히 Child의 인스턴스입니다.
- p는 실제로는 Parent 객체이지 Child가 아니므로, Child로의 다운캐스트에 실패해 false가 반환됩니다.
- c는 AnotherClass와 아무런 상속 관계가 없으므로 역시 false가 반환됩니다.
참고로 typeid 연산자를 사용해 타입을 비교하는 방법도 있습니다. 다만 typeid는 상속 관계를 고려하지 않고 정확히 일치하는 타입만 판별하므로, Java의 instanceof처럼 부모 클래스까지 포괄적으로 확인하려면 위 예제처럼 dynamic_cast를 활용하는 것이 바람직합니다.