C++ equivalent of java's instanceof C++ equivalent of java's instanceof java java

C++ equivalent of java's instanceof


Try using:

if(NewType* v = dynamic_cast<NewType*>(old)) {   // old was safely casted to NewType   v->doSomething();}

This requires your compiler to have rtti support enabled.

EDIT:I've had some good comments on this answer!

Every time you need to use a dynamic_cast (or instanceof) you'd better ask yourself whether it's a necessary thing. It's generally a sign of poor design.

Typical workarounds is putting the special behaviour for the class you are checking for into a virtual function on the base class or perhaps introducing something like a visitor where you can introduce specific behaviour for subclasses without changing the interface (except for adding the visitor acceptance interface of course).

As pointed out dynamic_cast doesn't come for free. A simple and consistently performing hack that handles most (but not all cases) is basically adding an enum representing all the possible types your class can have and check whether you got the right one.

if(old->getType() == BOX) {   Box* box = static_cast<Box*>(old);   // Do something box specific}

This is not good oo design, but it can be a workaround and its cost is more or less only a virtual function call. It also works regardless of RTTI is enabled or not.

Note that this approach doesn't support multiple levels of inheritance so if you're not careful you might end with code looking like this:

// Here we have a SpecialBox class that inherits Box, since it has its own type// we must check for both BOX or SPECIAL_BOXif(old->getType() == BOX || old->getType() == SPECIAL_BOX) {   Box* box = static_cast<Box*>(old);   // Do something box specific}


Depending on what you want to do you could do this:

template<typename Base, typename T>inline bool instanceof(const T*) {    return std::is_base_of<Base, T>::value;}

Use:

if (instanceof<BaseClass>(ptr)) { ... }

However, this purely operates on the types as known by the compiler.

Edit:

This code should work for polymorphic pointers:

template<typename Base, typename T>inline bool instanceof(const T *ptr) {    return dynamic_cast<const Base*>(ptr) != nullptr;}

Example: http://cpp.sh/6qir


Instanceof implementation without dynamic_cast

I think this question is still relevant today. Using the C++11 standard you are now able to implement a instanceof function without using dynamic_cast like this:

if (dynamic_cast<B*>(aPtr) != nullptr) {  // aPtr is instance of B} else {  // aPtr is NOT instance of B}

But you're still reliant on RTTI support. So here is my solution for this problem depending on some Macros and Metaprogramming Magic. The only drawback imho is that this approach does not work for multiple inheritance.

InstanceOfMacros.h

#include <set>#include <tuple>#include <typeindex>#define _EMPTY_BASE_TYPE_DECL() using BaseTypes = std::tuple<>;#define _BASE_TYPE_DECL(Class, BaseClass) \  using BaseTypes = decltype(std::tuple_cat(std::tuple<BaseClass>(), Class::BaseTypes()));#define _INSTANCE_OF_DECL_BODY(Class)                                 \  static const std::set<std::type_index> baseTypeContainer;           \  virtual bool instanceOfHelper(const std::type_index &_tidx) {       \    if (std::type_index(typeid(ThisType)) == _tidx) return true;      \    if (std::tuple_size<BaseTypes>::value == 0) return false;         \    return baseTypeContainer.find(_tidx) != baseTypeContainer.end();  \  }                                                                   \  template <typename... T>                                            \  static std::set<std::type_index> getTypeIndexes(std::tuple<T...>) { \    return std::set<std::type_index>{std::type_index(typeid(T))...};  \  }#define INSTANCE_OF_SUB_DECL(Class, BaseClass) \ protected:                                    \  using ThisType = Class;                      \  _BASE_TYPE_DECL(Class, BaseClass)            \  _INSTANCE_OF_DECL_BODY(Class)#define INSTANCE_OF_BASE_DECL(Class)                                                    \ protected:                                                                             \  using ThisType = Class;                                                               \  _EMPTY_BASE_TYPE_DECL()                                                               \  _INSTANCE_OF_DECL_BODY(Class)                                                         \ public:                                                                                \  template <typename Of>                                                                \  typename std::enable_if<std::is_base_of<Class, Of>::value, bool>::type instanceOf() { \    return instanceOfHelper(std::type_index(typeid(Of)));                               \  }#define INSTANCE_OF_IMPL(Class) \  const std::set<std::type_index> Class::baseTypeContainer = Class::getTypeIndexes(Class::BaseTypes());

Demo

You can then use this stuff (with caution) as follows:

DemoClassHierarchy.hpp*

#include "InstanceOfMacros.h"struct A {  virtual ~A() {}  INSTANCE_OF_BASE_DECL(A)};INSTANCE_OF_IMPL(A)struct B : public A {  virtual ~B() {}  INSTANCE_OF_SUB_DECL(B, A)};INSTANCE_OF_IMPL(B)struct C : public A {  virtual ~C() {}  INSTANCE_OF_SUB_DECL(C, A)};INSTANCE_OF_IMPL(C)struct D : public C {  virtual ~D() {}  INSTANCE_OF_SUB_DECL(D, C)};INSTANCE_OF_IMPL(D)

The following code presents a small demo to verify rudimentary the correct behavior.

InstanceOfDemo.cpp

#include <iostream>#include <memory>#include "DemoClassHierarchy.hpp"int main() {  A *a2aPtr = new A;  A *a2bPtr = new B;  std::shared_ptr<A> a2cPtr(new C);  C *c2dPtr = new D;  std::unique_ptr<A> a2dPtr(new D);  std::cout << "a2aPtr->instanceOf<A>(): expected=1, value=" << a2aPtr->instanceOf<A>() << std::endl;  std::cout << "a2aPtr->instanceOf<B>(): expected=0, value=" << a2aPtr->instanceOf<B>() << std::endl;  std::cout << "a2aPtr->instanceOf<C>(): expected=0, value=" << a2aPtr->instanceOf<C>() << std::endl;  std::cout << "a2aPtr->instanceOf<D>(): expected=0, value=" << a2aPtr->instanceOf<D>() << std::endl;  std::cout << std::endl;  std::cout << "a2bPtr->instanceOf<A>(): expected=1, value=" << a2bPtr->instanceOf<A>() << std::endl;  std::cout << "a2bPtr->instanceOf<B>(): expected=1, value=" << a2bPtr->instanceOf<B>() << std::endl;  std::cout << "a2bPtr->instanceOf<C>(): expected=0, value=" << a2bPtr->instanceOf<C>() << std::endl;  std::cout << "a2bPtr->instanceOf<D>(): expected=0, value=" << a2bPtr->instanceOf<D>() << std::endl;  std::cout << std::endl;  std::cout << "a2cPtr->instanceOf<A>(): expected=1, value=" << a2cPtr->instanceOf<A>() << std::endl;  std::cout << "a2cPtr->instanceOf<B>(): expected=0, value=" << a2cPtr->instanceOf<B>() << std::endl;  std::cout << "a2cPtr->instanceOf<C>(): expected=1, value=" << a2cPtr->instanceOf<C>() << std::endl;  std::cout << "a2cPtr->instanceOf<D>(): expected=0, value=" << a2cPtr->instanceOf<D>() << std::endl;  std::cout << std::endl;  std::cout << "c2dPtr->instanceOf<A>(): expected=1, value=" << c2dPtr->instanceOf<A>() << std::endl;  std::cout << "c2dPtr->instanceOf<B>(): expected=0, value=" << c2dPtr->instanceOf<B>() << std::endl;  std::cout << "c2dPtr->instanceOf<C>(): expected=1, value=" << c2dPtr->instanceOf<C>() << std::endl;  std::cout << "c2dPtr->instanceOf<D>(): expected=1, value=" << c2dPtr->instanceOf<D>() << std::endl;  std::cout << std::endl;  std::cout << "a2dPtr->instanceOf<A>(): expected=1, value=" << a2dPtr->instanceOf<A>() << std::endl;  std::cout << "a2dPtr->instanceOf<B>(): expected=0, value=" << a2dPtr->instanceOf<B>() << std::endl;  std::cout << "a2dPtr->instanceOf<C>(): expected=1, value=" << a2dPtr->instanceOf<C>() << std::endl;  std::cout << "a2dPtr->instanceOf<D>(): expected=1, value=" << a2dPtr->instanceOf<D>() << std::endl;  delete a2aPtr;  delete a2bPtr;  delete c2dPtr;  return 0;}

Output:

a2aPtr->instanceOf<A>(): expected=1, value=1a2aPtr->instanceOf<B>(): expected=0, value=0a2aPtr->instanceOf<C>(): expected=0, value=0a2aPtr->instanceOf<D>(): expected=0, value=0a2bPtr->instanceOf<A>(): expected=1, value=1a2bPtr->instanceOf<B>(): expected=1, value=1a2bPtr->instanceOf<C>(): expected=0, value=0a2bPtr->instanceOf<D>(): expected=0, value=0a2cPtr->instanceOf<A>(): expected=1, value=1a2cPtr->instanceOf<B>(): expected=0, value=0a2cPtr->instanceOf<C>(): expected=1, value=1a2cPtr->instanceOf<D>(): expected=0, value=0c2dPtr->instanceOf<A>(): expected=1, value=1c2dPtr->instanceOf<B>(): expected=0, value=0c2dPtr->instanceOf<C>(): expected=1, value=1c2dPtr->instanceOf<D>(): expected=1, value=1a2dPtr->instanceOf<A>(): expected=1, value=1a2dPtr->instanceOf<B>(): expected=0, value=0a2dPtr->instanceOf<C>(): expected=1, value=1a2dPtr->instanceOf<D>(): expected=1, value=1

Performance

The most interesting question which now arises is, if this evil stuff is more efficient than the usage of dynamic_cast. Therefore I've written a very basic performance measurement app.

InstanceOfPerformance.cpp

#include <chrono>#include <iostream>#include <string>#include "DemoClassHierarchy.hpp"template <typename Base, typename Derived, typename Duration>Duration instanceOfMeasurement(unsigned _loopCycles) {  auto start = std::chrono::high_resolution_clock::now();  volatile bool isInstanceOf = false;  for (unsigned i = 0; i < _loopCycles; ++i) {    Base *ptr = new Derived;    isInstanceOf = ptr->template instanceOf<Derived>();    delete ptr;  }  auto end = std::chrono::high_resolution_clock::now();  return std::chrono::duration_cast<Duration>(end - start);}template <typename Base, typename Derived, typename Duration>Duration dynamicCastMeasurement(unsigned _loopCycles) {  auto start = std::chrono::high_resolution_clock::now();  volatile bool isInstanceOf = false;  for (unsigned i = 0; i < _loopCycles; ++i) {    Base *ptr = new Derived;    isInstanceOf = dynamic_cast<Derived *>(ptr) != nullptr;    delete ptr;  }  auto end = std::chrono::high_resolution_clock::now();  return std::chrono::duration_cast<Duration>(end - start);}int main() {  unsigned testCycles = 10000000;  std::string unit = " us";  using DType = std::chrono::microseconds;  std::cout << "InstanceOf performance(A->D)  : " << instanceOfMeasurement<A, D, DType>(testCycles).count() << unit            << std::endl;  std::cout << "InstanceOf performance(A->C)  : " << instanceOfMeasurement<A, C, DType>(testCycles).count() << unit            << std::endl;  std::cout << "InstanceOf performance(A->B)  : " << instanceOfMeasurement<A, B, DType>(testCycles).count() << unit            << std::endl;  std::cout << "InstanceOf performance(A->A)  : " << instanceOfMeasurement<A, A, DType>(testCycles).count() << unit            << "\n"            << std::endl;  std::cout << "DynamicCast performance(A->D) : " << dynamicCastMeasurement<A, D, DType>(testCycles).count() << unit            << std::endl;  std::cout << "DynamicCast performance(A->C) : " << dynamicCastMeasurement<A, C, DType>(testCycles).count() << unit            << std::endl;  std::cout << "DynamicCast performance(A->B) : " << dynamicCastMeasurement<A, B, DType>(testCycles).count() << unit            << std::endl;  std::cout << "DynamicCast performance(A->A) : " << dynamicCastMeasurement<A, A, DType>(testCycles).count() << unit            << "\n"            << std::endl;  return 0;}

The results vary and are essentially based on the degree of compiler optimization. Compiling the performance measurement program using g++ -std=c++11 -O0 -o instanceof-performance InstanceOfPerformance.cpp the output on my local machine was:

InstanceOf performance(A->D)  : 699638 usInstanceOf performance(A->C)  : 642157 usInstanceOf performance(A->B)  : 671399 usInstanceOf performance(A->A)  : 626193 usDynamicCast performance(A->D) : 754937 usDynamicCast performance(A->C) : 706766 usDynamicCast performance(A->B) : 751353 usDynamicCast performance(A->A) : 676853 us

Mhm, this result was very sobering, because the timings demonstrates that the new approach is not much faster compared to the dynamic_cast approach. It is even less efficient for the special test case which tests if a pointer of A is an instance ofA. BUT the tide turns by tuning our binary using compiler otpimization. The respective compiler command is g++ -std=c++11 -O3 -o instanceof-performance InstanceOfPerformance.cpp. The result on my local machine was amazing:

InstanceOf performance(A->D)  : 3035 usInstanceOf performance(A->C)  : 5030 usInstanceOf performance(A->B)  : 5250 usInstanceOf performance(A->A)  : 3021 usDynamicCast performance(A->D) : 666903 usDynamicCast performance(A->C) : 698567 usDynamicCast performance(A->B) : 727368 usDynamicCast performance(A->A) : 3098 us

If you are not reliant on multiple inheritance, are no opponent of good old C macros, RTTI and template metaprogramming and are not too lazy to add some small instructions to the classes of your class hierarchy, then this approach can boost your application a little bit with respect to its performance, if you often end up with checking the instance of a pointer. But use it with caution. There is no warranty for the correctness of this approach.

Note: All demos were compiled using clang (Apple LLVM version 9.0.0 (clang-900.0.39.2)) under macOS Sierra on a MacBook Pro Mid 2012.

Edit:I've also tested the performance on a Linux machine using gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609. On this platform the perfomance benefit was not so significant as on macOs with clang.

Output (without compiler optimization):

InstanceOf performance(A->D)  : 390768 usInstanceOf performance(A->C)  : 333994 usInstanceOf performance(A->B)  : 334596 usInstanceOf performance(A->A)  : 300959 usDynamicCast performance(A->D) : 331942 usDynamicCast performance(A->C) : 303715 usDynamicCast performance(A->B) : 400262 usDynamicCast performance(A->A) : 324942 us

Output (with compiler optimization):

InstanceOf performance(A->D)  : 209501 usInstanceOf performance(A->C)  : 208727 usInstanceOf performance(A->B)  : 207815 usInstanceOf performance(A->A)  : 197953 usDynamicCast performance(A->D) : 259417 usDynamicCast performance(A->C) : 256203 usDynamicCast performance(A->B) : 261202 usDynamicCast performance(A->A) : 193535 us