Как определить фактический тип объекта во время выполнения на С++;
Допустим, у нас есть иерархия классов. Внизу у нас есть Base и наверху Derived.
Как определить класс объекта, даже если он преобразован в указатель базового класса.
Base* b = new Derived():
typeid(b).name(); // i want this to tell me that this is actually derived not base object
есть ли какой-либо иной способ, кроме ручной реализации строкового поля или такой и виртуальной функции get?
PS: Я говорю о независимом от компилятора решении
Ответы
Ответ 1
убедитесь, что базовый класс имеет хотя бы один виртуальный метод, включите <typeinfo>
и используйте свой текущий код только с дополнительным разыменованием typeid(*b).name()
.
пропустите, обратите внимание, что вызов typeid
- это одно место на С++, где вы можете разыменовать нулевой указатель с четко определенным поведением, что означает, что он может генерировать исключение:
С++ 11 §5.2.8/2:
"Если выражение glvalue получается, применяя унарный оператор *
к указатель и указатель - это значение нулевого указателя (4.10), выражение typeid
генерирует исключение std::bad_typeid
(18.7.3)."
Ответ 2
Если все, что вы хотите сделать, это найти, если b
на самом деле указывает на Derived
, просто используйте dynamic_cast()
:
if (dynamic_cast<Derived*>(b)) { ... }
dynamic_cast
возвращает нулевой указатель, если фактический тип времени выполнения объекта, на который указывает b
, не Derived
(или класс, полученный из Derived
). В отличие от члена name()
std::type_info
, это компилятор-инвариант.
Обратите внимание, что это работает только в том случае, если Base
имеет по крайней мере одну виртуальную функцию-член. Это должно быть так или иначе, поскольку вы манипулируете типами, полученными из него с помощью базового указателя, поэтому он должен иметь виртуальный деструктор.