Как проверить, является ли тип объекта конкретным подclassом в C ++?

Я думал о том, как использовать typeid() но я не знаю, как спросить, является ли этот тип подclassом другого classа (который, кстати, является абстрактным)

Вы действительно не должны. Если ваша программа должна знать, какой class является объектом, это обычно указывает на недостаток дизайна. Посмотрите, сможете ли вы получить нужное поведение с помощью виртуальных функций. Кроме того, дополнительная информация о том, что вы пытаетесь сделать, поможет.

Я предполагаю, что у вас есть такая ситуация:

 class Base; class A : public Base {...}; class B : public Base {...}; void foo(Base *p) { if(/* p is A */) /* do X */ else /* do Y */ } 

Если это то, что у вас есть, попробуйте сделать что-то вроде этого:

 class Base { virtual void bar() = 0; }; class A : public Base { void bar() {/* do X */} }; class B : public Base { void bar() {/* do Y */} }; void foo(Base *p) { p->bar(); } 

Изменить: Поскольку дебаты об этом ответе продолжаются после стольких лет, я подумал, что должен бросить некоторые ссылки. Если у вас есть указатель или ссылка на базовый class, и ваш код должен знать производный class объекта, то он нарушает принцип замещения Лискова . Дядя Боб называет это « анафемой объектно-ориентированного дизайна ».

 class Base { public: virtual ~Base() {} }; class D1: public Base {}; class D2: public Base {}; int main(int argc,char* argv[]); { D1 d1; D2 d2; Base* x = (argc > 2)?&d1:&d2; if (dynamic_cast(x) == nullptr) { std::cout << "NOT A D2" << std::endl; } if (dynamic_cast(x) == nullptr) { std::cout << "NOT A D1" << std::endl; } } 

Вы можете сделать это с помощью dynamic_cast (по крайней мере, для полиморфных типов).

Собственно, со второй мыслью – вы не можете определить, является ли СПЕЦИФИЧЕСКИ конкретным типом с dynamic_cast но вы можете определить, является ли он этим типом или любым его подclassом.

 template  bool IsType(const SrcType* src) { return dynamic_cast(src) != nullptr; } 

dynamic_cast может определить, содержит ли тип целевой тип в иерархии наследования (да, это малоизвестная функция, если B наследует от A и C , она может превратить A* непосредственно в C* ). typeid() может определять точный тип объекта. Однако они должны использоваться очень экономно. Как уже упоминалось, вы всегда должны избегать динамической идентификации типа, поскольку это указывает на недостаток дизайна. (также, если вы знаете, что объект определен точно для целевого типа, вы можете сделать downcast с static_cast . Boost предлагает polymorphic_downcast который будет делать downcast с dynamic_cast и assert в режиме отладки, а в режиме выпуска он просто будет использовать static_cast ).

Я не согласен, что вы никогда не захотите проверять тип объекта на C ++. Если вы можете этого избежать, я согласен, что вы должны. Говорить, что НИКОГДА НИКОГДА не делайте этого ни при каких обстоятельствах, это заходит слишком далеко. Вы можете сделать это на большом количестве языков, и это может сделать вашу жизнь намного легче. Говард Пинсли, например, показал нам, как в его должности на C #.

Я много работаю с Qt Framework. В общем, я моделирую то, что я делаю после того, как они делают вещи (по крайней мере, когда они работают в их рамках). Класс QObject является базовым classом всех объектов Qt. Этот class имеет функции isWidgetType () и isWindowType () в качестве быстрой проверки подclassа. Так почему бы вам не проверить свои производные classы, которые сопоставимы по своей природе? Ниже приведено описание QObject некоторых из этих других сообщений:

 class MyQObject : public QObject { public: MyQObject( QObject *parent = 0 ) : QObject( parent ){} ~MyQObject(){} static bool isThisType( const QObject *qObj ) { return ( dynamic_cast(qObj) != NULL ); } }; 

И затем, когда вы передаете указатель на QObject, вы можете проверить, указывает ли он на ваш производный class, вызвав статическую функцию-член:

 if( MyQObject::isThisType( qObjPtr ) ) qDebug() << "This is a MyQObject!"; 

Я не знаю, правильно ли я понимаю вашу проблему, поэтому позвольте мне повторить это своими словами …

Задача: заданные classы B и D определяют, является ли D подclassом B (или наоборот)

Решение. Используйте магию шаблона! Хорошо, серьезно вам нужно взглянуть на LOKI, отличную библиотеку мета-программирования шаблонов, созданную легендарным автором C ++ Андреем Александреску.

В частности, загрузите LOKI и TypeManip.h заголовок TypeManip.h из него в исходный код, затем используйте SuperSubclass classа SuperSubclass следующим образом:

 if(SuperSubClass::value) { ... } 

Согласно документации, значение SuperSubClass::value будет истинным, если B является общедоступной базой D или если B и D являются псевдонимами того же типа.

т.е. либо D является подclassом B либо D является тем же, что и B

Надеюсь, это поможет.

редактировать:

Обратите внимание, что оценка значения SuperSubClass::value происходит во время компиляции, в отличие от некоторых методов, которые используют dynamic_cast , поэтому нет штрафа за использование этой системы во время выполнения.

В c # вы можете просто сказать:

 if (myObj is Car) { } 
 #include  #include  class Base { public: virtual ~Base() {} template bool isA() { return (dynamic_cast(this) != NULL); } }; class D1: public Base {}; class D2: public Base {}; class D22: public D2 {}; int main(int argc,char* argv[]); { D1* d1 = new D1(); D2* d2 = new D2(); D22* d22 = new D22(); Base* x = d22; if( x->isA() ) { std::cout << "IS A D22" << std::endl; } if( x->isA() ) { std::cout << "IS A D2" << std::endl; } if( x->isA() ) { std::cout << "IS A D1" << std::endl; } if(x->isA() ) { std::cout << "IS A Base" << std::endl; } } 

Результат:

 IS A D22 IS A D2 IS A Base 

Вы можете делать это только во время компиляции с использованием шаблонов, если только вы не используете RTTI.

Он позволяет использовать функцию typeid, которая даст указатель на структуру type_info, которая содержит информацию о типе.

Читайте на нем в Википедии

Я думал о том, как использовать typeid()

Ну, да, это можно сделать, сравнив: typeid().name() . Если мы возьмем уже описанную ситуацию, где:

 class Base; class A : public Base {...}; class B : public Base {...}; void foo(Base *p) { if(/* p is A */) /* do X */ else /* do Y */ } 

Возможной реализацией foo(Base *p) будет:

 #include  void foo(Base *p) { if(typeid(*p) == typeid(A)) { // the pointer is pointing to the derived class A } else if (typeid(*p).name() == typeid(B).name()) { // the pointer is pointing to the derived class B } } 
Interesting Posts

Графическая карта с Clarkdale

Android – увеличение / уменьшение изображения RelativeLayout с распространением / пинчем

Разделить строку с разделителями на C

SSH запрашивает пароль, даже если установлен открытый ключ

LINQ to SQL: несколько объединений в нескольких столбцах. Это возможно?

Создание UUID V5. Что такое имя и пространство имен?

Android – нижний колонтитул прокручивается с экрана при использовании в CoordinatorLayout

Вызов обратных вызовов с помощью Mockito

Поставщик Entity Framework не найден для поставщика услуг «MySql.Data.MySqlClient» ADO.NET

Как я могу заставить Visual Studio 2008 Window Forms создать форму, которая реализует абстрактный базовый class?

Как я могу сделать столбцы Bootstrap одинаковой высоты?

Почему Enumerable.All возвращает true для пустой последовательности?

Закладки Google считают, что я в Португалии

Создать массив совпадений регулярных выражений

Вызов статического метода с reflectionм

Давайте будем гением компьютера.