Каков предпочтительный метод для достижения C ++ эквивалента Java instanceof
?
java
c++
oop
instanceof
Ювал Адам
источник
источник
Ответы:
Попробуйте использовать:
Это требует, чтобы ваш компилятор включил поддержку rtti.
РЕДАКТИРОВАТЬ: у меня были некоторые хорошие комментарии к этому ответу!
Каждый раз, когда вам нужно использовать dynamic_cast (или instanceof), вам лучше спросить себя, является ли это необходимым. Это вообще признак плохого дизайна.
Типичные обходные пути - это размещение специального поведения для класса, который вы проверяете, в виртуальной функции базового класса или, возможно, введение чего-то вроде посетителя, где вы можете ввести определенное поведение для подклассов без изменения интерфейса (за исключением добавления интерфейса принятия посетителем курс).
Как указано, dynamic_cast не предоставляется бесплатно. Простой и последовательно выполняемый хак, который обрабатывает большинство (но не все случаи), в основном добавляет enum, представляющий все возможные типы, которые может иметь ваш класс, и проверяет, правильно ли вы выбрали.
Это не очень хороший дизайн, но это может быть обходной путь, и его стоимость более или менее только вызов виртуальной функции. Он также работает независимо от того, включен RTTI или нет.
Обратите внимание, что этот подход не поддерживает несколько уровней наследования, поэтому, если вы не будете осторожны, вы можете получить код, похожий на этот:
источник
В зависимости от того, что вы хотите сделать, вы можете сделать это:
Использование:
Однако это чисто работает с типами, известными компилятору.
Редактировать:
Этот код должен работать для полиморфных указателей:
Пример: http://cpp.sh/6qir
источник
Экземпляр реализации без dynamic_cast
Я думаю, что этот вопрос все еще актуален сегодня. Используя стандарт C ++ 11, вы теперь можете реализовать
instanceof
функцию без использованияdynamic_cast
этого:Но вы все еще полагаетесь на
RTTI
поддержку. Итак, вот мое решение этой проблемы в зависимости от некоторых макросов и метапрограммирования магии. Единственный недостаток imho заключается в том, что этот подход не работает для множественного наследования .InstanceOfMacros.h
демонстрация
Затем вы можете использовать этот материал ( с осторожностью ) следующим образом:
DemoClassHierarchy.hpp *
В следующем коде представлена небольшая демонстрация для проверки правильного поведения.
InstanceOfDemo.cpp
Вывод:
Производительность
Самый интересный вопрос, который сейчас возникает, заключается в том, является ли этот злой материал более эффективным, чем использование
dynamic_cast
. Поэтому я написал очень простое приложение для измерения производительности.InstanceOfPerformance.cpp
Результаты различаются и в основном зависят от степени оптимизации компилятора. Компиляция программы измерения производительности с использованием
g++ -std=c++11 -O0 -o instanceof-performance InstanceOfPerformance.cpp
вывода на моем локальном компьютере:Мм, этот результат был очень отрезвляющим, потому что время показывает, что новый подход не намного быстрее по сравнению с
dynamic_cast
подходом. Это еще менее эффективно для специального теста, который проверяет, является ли указательA
экземпляраA
. НО прилив меняется, настраивая наш бинарный файл с помощью отпимеризации компилятора. Соответствующая команда компилятораg++ -std=c++11 -O3 -o instanceof-performance InstanceOfPerformance.cpp
. Результат на моей локальной машине был потрясающим:Если вы не полагаетесь на множественное наследование, не являетесь противником старых добрых макросов C, RTTI и шаблонного метапрограммирования и не поленитесь добавить небольшие инструкции к классам иерархии классов, тогда этот подход может немного улучшить ваше приложение. в отношении его производительности, если вам часто приходится проверять экземпляр указателя. Но используйте это с осторожностью . На правильность такого подхода нет никаких гарантий.
Примечание. Все демонстрационные версии были скомпилированы с использованием
clang (Apple LLVM version 9.0.0 (clang-900.0.39.2))
MacOS Sierra на MacBook Pro Mid 2012.Изменить: я также проверил производительность на машине Linux с помощью
gcc (Ubuntu 5.4.0-6ubuntu1~16.04.9) 5.4.0 20160609
. На этой платформе выигрыш в производительности был не таким значительным, как на macO с clang.Вывод (без оптимизации компилятора):
Вывод (с оптимизацией компилятора):
источник
dynamic_cast
как известно, неэффективно. Он пересекает иерархию наследования и является единственным решением, если у вас есть несколько уровней наследования, и вам необходимо проверить, является ли объект экземпляром какого-либо одного из типов в его иерархии типов.Но если более ограниченная форма
instanceof
проверки только проверяет, является ли объект именно того типа, который вы указали, достаточно для ваших нужд, приведенная ниже функция будет намного более эффективной:Вот пример того, как вы бы вызвали функцию выше:
Вы должны указать тип шаблона
A
(как тип, который вы проверяете) и передать в качестве аргумента объект, который вы хотите проверить (из какого типа шаблонаK
будет выведен вывод).источник
источник
instanceof
запрашивает динамический тип, но в этом ответе динамический и статический тип всегда соответствуют.Это прекрасно работает для меня, используя Code :: Blocks IDE с компилятором GCC
источник
typeid
», что, хотя и неверно («Нет гарантии, что все оценки выражения typeid для одного и того же типа будут ссылаться на один и тот же экземпляр std :: type_infoassert(typeid(A) == typeid(A)); /* not guaranteed */
», см. cppreference.com ), указывает на то, что он хотя бы попытался ответить на вопрос, хотя и безуспешно, потому что он пренебрег минимальным рабочим примером.