RTTI — механизм, позволяющий получать информацию о типе объекта во время выполнения программы. Состоит из двух ключевых компонентов:
typeid
— оператор для получения информации о типеdynamic_cast
— оператор для безопасного приведения типовДля работы RTTI необходимо:
-frtti
(включено по умолчанию в большинстве компиляторов)dynamic_cast
)# Явное отключение RTTI (например, для embedded систем)
g++ -fno-rtti program.cpp
#include <typeinfo>
Base* ptr = new Derived();
const std::type_info& ti = typeid(*ptr);
std::cout << "Type name: " << ti.name() << std::endl;
if (ti == typeid(Derived)) {
std::cout << "Object is Derived" << std::endl;
}
std::type_info
name()
возвращает implementation-defined имя типаBase* basePtr = new Derived();
// Безопасное приведение вниз по иерархии
Derived* derivedPtr = dynamic_cast<Derived*>(basePtr);
if (derivedPtr) {
// Приведение успешно
} else {
// Тип не соответствует
}
nullptr
для указателей при неудачеstd::bad_cast
для ссылок при неудачеДля каждого полиморфного класса компилятор создает:
std::type_info
Пример расположения в памяти:
|---------------------|
| Vtable для Derived |
|---------------------|
| vfunc1_ptr |
| vfunc2_ptr |
| ... |
| RTTI-ptr ---------> |---> type_info для Derived
|---------------------|
Производительность:
dynamic_cast
требует времени на проверку иерархииtypeid
обычно быстрее, но все равно требует доступа к vtableРазмер бинарника:
Портативность:
type_info::name()
зависит от компилятораВиртуальные функции (полиморфизм):
class Base {
public:
virtual std::string getType() const { return "Base"; }
};
Ручная система типов:
enum class Type { Base, Derived };
class Base {
virtual Type getType() const { return Type::Base; }
};
Шаблонный подход (CRTP):
template<typename Derived>
class Base {
static std::string getType() { return typeid(Derived).name(); }
};
class GameObject {
public:
virtual ```GameObject() = default;
};
class Enemy : public GameObject { /* ... */ };
GameObject* createObject(const std::string& type) {
if (type == "enemy") return new Enemy();
return nullptr;
}
void processEnemy(GameObject* obj) {
if (dynamic_cast<Enemy*>(obj)) {
// Работаем с Enemy
}
}
void serialize(const GameObject& obj) {
if (typeid(obj) == typeid(Enemy)) {
// Специальная сериализация для Enemy
} else {
// Общая сериализация
}
}
Резюмируем: RTTI предоставляет мощные возможности для работы с типами во время выполнения, но требует осторожного использования из-за накладных расходов. В высокопроизводительном коде часто предпочитают альтернативные подходы, но для общего применения и в инструментах разработки RTTI остается ценным инструментом.