Run-Time Type Checking in C++

Introduction

A frequently asked question is: “How can I identify/check the type of an object in C++ at run-time?” Let me show you by resolving a simple problem!

Complete the program to display “Bark!” in the first call of CFoo::AnimalSays and “Miaou!” in the second one.

class Animal {/*...*/};
class Dog : public Animal {/*...*/};
class Cat : public Animal {/*...*/};
class CFoo
{
public:
  void AnimalSays(Animal*) {/*...*/}
};

int main(int argc, char* argv[])
{
  Dog   rex;
  Cat   kitty;
  CFoo  foo;

  foo.AnimalSays(&rex);
  foo.AnimalSays(&kitty);

  return 0;
}

In other words, you have to find a method to verify at run-time whether the function CFoo::AnimalSays takes, as an argument, a pointer to an object of type Dog or a pointer to an object of type Cat.

One First Try

The first idea is to add a member variable that stores info about the type.

#include <iostream>

class Animal
{
public:
   enum AnimalType {TypeDog, TypeCat};
};

class Dog : public Animal
{
public:
   Dog() : m_type(TypeDog) {}
   const AnimalType m_type;
};

class Cat : public Animal
{
public:
   Cat() : m_type(TypeCat) {}
   const AnimalType m_type;
};

class CFoo
{
public:
   void AnimalSays(Animal*);
};

int main(int argc, char* argv[])
{
   Dog   rex;
   Cat   kitty;
   CFoo  foo;

   foo.AnimalSays(&rex);
   foo.AnimalSays(&kitty);

   return 0;
}

void CFoo::AnimalSays(Animal* pAnimal)
{
   if(((Dog*)pAnimal)->m_type == Animal::TypeDog)
      std::cout << "Bark! ";
   else if(((Cat*)pAnimal)->m_type == Animal::TypeCat)
      std::cout << "Miaou! ";
}

Now, please take a look at the CFoo::AnimalSays function implementation and imagine that you have not only two but fifty-two animal types (in other words, classes derived from Animal)! Quite ugly! It will be hard to write it with no errors and it also will be hard to read/modify/maintain. However, there can be even worse solutions…

More by Author

Must Read