Run Time Type Information (RTTI) and typeid()

RTTI Alternatives for Performance

Are there any alternatives to RTTI for identifying types at runtime in performance-critical systems?

Illustration representing computer hardware

Yes, there are several alternatives to RTTI for identifying types at runtime in performance-critical systems. These alternatives often provide better performance at the cost of some flexibility or additional implementation effort. Here are some common approaches:

Virtual Function Approach

Use a virtual function to return a type identifier. This is faster than RTTI and doesn't require additional memory for type information.

enum class MonsterType { Base, Dragon, Goblin };

class Monster {
 public:
  virtual ~Monster() = default;
  virtual MonsterType getType() const {
    return MonsterType::Base;
  }
};

class Dragon : public Monster {
 public:
  MonsterType getType() const override {
    return MonsterType::Dragon;
  }
};

class Goblin : public Monster {
 public:
  MonsterType getType() const override {
    return MonsterType::Goblin;
  }
};

void handleMonster(const Monster& monster) {
  switch (monster.getType()) {
    case MonsterType::Dragon:
      std::cout << "Handling a Dragon\n";
      break;
    case MonsterType::Goblin:
      std::cout << "Handling a Goblin\n";
      break;
    default:
      std::cout << "Handling a generic Monster\n";
  }
}

Tag Dispatch

Use tag classes to dispatch to the correct function at compile-time. This approach is fast and doesn't require virtual functions.

struct MonsterTag {};
struct DragonTag : MonsterTag {};
struct GoblinTag : MonsterTag {};

class Monster {
 public:
  virtual ~Monster() = default;
  virtual MonsterTag getTag() const {
    return MonsterTag{};
  }
};

class Dragon : public Monster {
 public:
  DragonTag getTag() const override {
    return DragonTag{};
  }
};

class Goblin : public Monster {
 public:
  GoblinTag getTag() const override {
    return GoblinTag{};
  }
};

void handleMonster(
  const Monster& monster, MonsterTag
) {
  std::cout << "Handling a generic Monster\n";
}

void handleMonster(
  const Monster& monster, DragonTag
) {
  std::cout << "Handling a Dragon\n";
}

void handleMonster(
  const Monster& monster, GoblinTag
) {
  std::cout << "Handling a Goblin\n";
}

void processMonster(const Monster& monster) {
  handleMonster(monster, monster.getTag());  
}

Curiously Recurring Template Pattern (CRTP)

Use CRTP to implement static polymorphism, avoiding the need for virtual functions and RTTI.

template<typename Derived>
class Monster {
 public:
  void process() {
    static_cast<Derived*>(this)->processImpl();
  }
};

class Dragon : public Monster<Dragon> {
 public:
  void processImpl() {
    std::cout << "Processing a Dragon\n";
  }
};

class Goblin : public Monster<Goblin> {
 public:
  void processImpl() {
    std::cout << "Processing a Goblin\n";
  }
};

template<typename T>
void handleMonster(Monster<T>& monster) {
  monster.process();
}

Type Erasure with Function Pointers

Use type erasure to store type-specific behavior without virtual functions or RTTI.

#include <functional>

class Monster {
 public:
  template<typename T>
  Monster(T&& obj) :
    object_(new T(std::forward<T>(obj))),
    process_([](void* obj) {
      static_cast<T*>(obj)->process();
    })
  {}

  void process() {
    process_(object_);
  }

 private:
  void* object_;
  std::function<void(void*)> process_;
};

struct Dragon {
  void process() {
    std::cout << "Processing Dragon\n";
  }
};

struct Goblin {
  void process() {
    std::cout << "Processing Goblin\n";
  }
};

void handleMonster(Monster& monster) {
  monster.process();
}

Each of these alternatives has its own trade-offs. The virtual function approach is simple but still incurs the cost of virtual function calls. Tag dispatch and CRTP provide compile-time polymorphism but can lead to code bloat. Type erasure provides runtime flexibility without RTTI but involves more complex implementation.

Choose the approach that best fits your specific performance requirements and design constraints. In many cases, these alternatives can provide significant performance improvements over RTTI in critical code paths.

This Question is from the Lesson:

Run Time Type Information (RTTI) and typeid()

Learn to identify and react to object types at runtime using RTTI, dynamic casting and the typeid() operator

Answers to questions are automatically generated and may not have been reviewed.

This Question is from the Lesson:

Run Time Type Information (RTTI) and typeid()

Learn to identify and react to object types at runtime using RTTI, dynamic casting and the typeid() operator

A computer programmer
Part of the course:

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Free, unlimited access

This course includes:

  • 124 Lessons
  • 550+ Code Samples
  • 96% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved