Я хочу знать, что современный C ++ 11 эквивалент Java в instanceof. Я видел это ТАК сообщение но он довольно старый и ему было интересно, есть ли более современное и лучшее решение в C ++ 11?
Я надеялся, что есть возможность использовать конструкцию switch, не прибегая к ручному классу enum.
class A {
};
class B : public A {
}
class C : public A {
}
on_event(A& obj)
{
switch (obj) {
case A:
case B:
case C:
}
}
Мой базовый класс не имеет никаких виртуальных методов или функций. Я представляю дерево выражений для парсера, а базовый класс — это просто полиморфный держатель — как ADT в Haskell / OCaml.
Тот же ответ все еще применяется, и всегда был таким в C ++:
if (C * p = dynamic_cast<C *>(&obj))
{
// The type of obj is or is derived from C
}
else
{
// obj is not a C
}
Эта конструкция требует A
быть полиморфным, то есть иметь виртуальные функции-члены.
Также обратите внимание, что это поведение отличается от сравнения typeid(obj) == typeid(C)
, поскольку последний проверяет точную идентичность типа, тогда как динамическое приведение, а также Java instanceof
только для проверки, чтобы целевой тип был базовым классом типа самого производного объекта.
В C ++ простые старые данные (POD) не имеют информации о типе времени выполнения. Все описанные классы занимают ровно 1 байт и имеют идентичные представления времени выполнения в любом компиляторе с пустой оптимизацией базового класса.
Таким образом, то, что вы хотите, не может быть сделано.
Добавление виртуального деструктора в базовый класс добавляет в RTTI и dynamic_cast
служба поддержки.
Добавление enum
или же int
поле к базе, которое инициализируется по-разному для каждого производного класса, также работает.
Еще один вариант — создать шаблонную функцию и сохранить указатель на нее, например, так:
using my_type_id=void(*)();
template<class>void get_my_type_id_helper(){};
template<class T> my_type_id get_my_type_id(){return get_my_type_id_helper<T>;}
а затем хранить my_type_id
в A
инициализируется соответствующим образом. Это переизобретает RTTI, и, если вам нужно больше возможностей, вы будете использовать C ++ RTTI.
В C ++ вы платите только за то, что просите: вы можете попросить классы без RTTI, которые вы сделали, и получить это.
RTTI — это информация о типе времени выполнения. POD — это простые старые данные, термин C ++ 03. Многие классы не являются POD: проще всего добавить virtual
деструктор. C ++ 11 имеет более мелкозернистую стандартную компоновку и совокупные термины.
Технически RTTI и POD не являются противоположностями друг другу: существуют классы без RTTI, которые не являются POD.
Обратите внимание, что MSVC имеет опции не генерировать RTTI, и его агрессивное сворачивание Comdat может нарушить ручной RTTI, который я делал выше, в обоих случаях в нарушение стандарта.
Может быть, вы заинтересованы в ответе, который я разместил в упомянутом вами старом посте SO.
https://stackoverflow.com/a/49296405/1266588
Ответ представляет собой реализацию instanceof
без использования dynamic_cast
основанный на C ++ 11, метапрограммирование шаблона а также RTTI. Небольшое приложение для измерения производительности демонстрирует, что оно более эффективно, чем dynamic_cast
если вы используете оптимизацию компилятора.
Не делай этого. В большинстве случаев вы должны пересмотреть свой дизайн, когда вы просите instanceof
или же dynamic_cast
,
Зачем? Вы, скорее всего, нарушаете Принцип подстановки Лискова.
Как насчет этого подхода:
class A {
public:
virtual void action();
virtual ~A();
};
class B : public A {
public: void action() override;
};
class C : public A {
public: void action() override;
};
void on_event(A& obj)
{
obj.action();
}
Обратите внимание, что, как указал @Yakk, вам нужен хотя бы один virtual
метод в любом случае, чтобы получить динамический полиморфизм. И есть правило, которое гласит: если у вас есть хотя бы один виртуальный метод, всегда также пишите виртуальный деструктор в базовом классе.
Вы можете сделать все это с помощью шаблонов и специализаций или маркировки типов, но я беру из вашего вопроса — пришедшего с Java — вы пока не хотите туда идти. Вы действительно лайк виртуальные методы, не так ли? Извините, что вы должны пометить их в C ++.
Если вы хотите ограничить себя типами, известными во время компиляции (вместо того, чтобы работать через указатели на экземплярах классов с vtables) — тогда C ++ 11 и более поздние версии имеют instanceof
эквивалент: это станд :: is_base_of.
Вы также можете проверить станд :: шаблона is_convertible а также станд :: is_same.