How to check if an object type is a specific subclass in C ++?

I was thinking about how to use typeid() , but I don't know how to ask if this type is a subclass of another class (which, by the way, is abstract)

+59
c ++ class subclass
Nov 21 '08 at 3:41
source share
11 answers

You really shouldn't. If your program needs to know which class is the object, this usually indicates a design flaw. See if you can get the right behavior with virtual functions. In addition, additional information about what you are trying to do will help.

I assume you have a situation like this:

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

If this is what you have, try doing something like this:

 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(); } 

Edit: As the debate about this answer continues after so many years, I thought I should throw some links. If you have a pointer or a reference to the base class, and your code must know the derived class of the object, then it violates the Liskov substitution principle , Uncle Bob calls it the β€œ anathema of object-oriented design ”.

+41
Nov 21 '08 at 3:57
source share

 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<D2*>(x) == nullptr) { std::cout << "NOT A D2" << std::endl; } if (dynamic_cast<D1*>(x) == nullptr) { std::cout << "NOT A D1" << std::endl; } } 
+91
Nov 21 '08 at 4:01
source share

You can do this with dynamic_cast (at least for polymorphic types).

Actually, for the second time - you cannot determine whether it is an SPECIALLY specific type with dynamic_cast - but you can determine whether it is this type or any subclass of it.

 template <class DstType, class SrcType> bool IsType(const SrcType* src) { return dynamic_cast<const DstType*>(src) != nullptr; } 
+21
Nov 21 '08 at 4:05
source share

dynamic_cast can determine if a type contains a target type somewhere in the inheritance hierarchy (yes, this is a little-known function that, if B inherits from A and C , can turn A* directly into C* ). typeid() can determine the exact type of an object. However, they should be used very sparingly. As already mentioned, you should always avoid dynamic type identification, as this indicates a design flaw. (also, if you know that the object is specific to the target type, you can do down down with static_cast . Boost offers polymorphic_downcast , which will do downcast with dynamic_cast and assert in debug mode, and in release mode it will just use static_cast ).

+6
Nov 21 '08 at 4:49
source share

I do not know if I understand your problem correctly, so let me repeat it with words ...

Problem: The given classes B and D determine if D subclass of B (or vice versa?)

Solution: use template magic! Well, seriously, you need to take a look at LOKI, an excellent template meta-programming library created by the legendary C ++ author Andrei Alexandruscu.

In particular, download LOKI and include the TypeManip.h header from it in the source code, then use the SuperSubclass class SuperSubclass as follows:

 if(SuperSubClass<B,D>::value) { ... } 

According to the documentation, SuperSubClass<B,D>::value will be true if B is the public base of D , or if B and D are aliases of the same type.

i.e. either D is a subclass of B or D is the same as B

Hope this helps.

change

Note that evaluating SuperSubClass<B,D>::value occurs at compile time, unlike some methods that use dynamic_cast , so there’s no penalty for using this system at runtime.

+4
Nov 21 '08 at 16:43
source share

I do not agree that you will never want to check the type of an object in C ++. If you can avoid this, I agree that you should. To say that NEVER do this under any circumstances, it goes too far. You can do it in a lot of languages, and it can make your life a lot easier. Howard Pinsley, for example, showed us how in his post in C #.

I work a lot with the Qt Framework. In general, I model what I do after they do things (at least when they work within their framework). The QObject class is the base class of all Qt objects. This class has the functions isWidgetType () and isWindowType () as a quick check for the subclass. So why not check out your own derived classes, which is comparable in nature? The following is a QObject description of some of the other posts:

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

And then, when you pass a pointer to a QObject, you can check if it points to your derived class by calling a static member function:

 if( MyQObject::isThisType( qObjPtr ) ) qDebug() << "This is a MyQObject!"; 
+4
Dec 19 '15 at
source share
 #include <stdio.h> #include <iostream.h> class Base { public: virtual ~Base() {} template<typename T> bool isA() { return (dynamic_cast<T*>(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<D22>() ) { std::cout << "IS A D22" << std::endl; } if( x->isA<D2>() ) { std::cout << "IS A D2" << std::endl; } if( x->isA<D1>() ) { std::cout << "IS A D1" << std::endl; } if(x->isA<Base>() ) { std::cout << "IS A Base" << std::endl; } } 

Result:

 IS A D22 IS A D2 IS A Base 
+2
May 26 '17 at 17:00
source share

In C #, you can just say:

 if (myObj is Car) { } 
+1
Nov 21 '08 at 3:49 a.m.
source share

You can only do this at compile time using templates, unless you are using RTTI.

It allows you to use the typeid function, which will give a pointer to the type_info structure, which contains type information.

Read it on Wikipedia

+1
Nov 21 '08 at 3:55
source share

I was thinking about how to use typeid() ...

Well, yes, this can be done by comparing: typeid().name() . If we take the situation already described, where:

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

A possible implementation of foo(Base *p) would be:

 #include <typeinfo> 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 } } 
0
Jun 06 '17 at 22:31 on
source share

The code below demonstrates 3 different ways to do this:

  • virtual function
  • Typeid
  • dynamic_cast
 #include <iostream> #include <typeinfo> #include <typeindex> enum class Type {Base, A, B}; class Base { public: virtual ~Base() = default; virtual Type type() const { return Type::Base; } }; class A : public Base { Type type() const override { return Type::A; } }; class B : public Base { Type type() const override { return Type::B; } }; int main() { const char *typemsg; A a; B b; Base *base = &a; // = &b; !!!!!!!!!!!!!!!!! Base &bbb = *base; // below you can replace base with &bbb and get the same results // USING virtual function // ====================== // classes need to be in your control switch(base->type()) { case Type::A: typemsg = "type A"; break; case Type::B: typemsg = "type B"; break; default: typemsg = "unknown"; } std::cout << typemsg << std::endl; // USING typeid // ====================== // needs RTTI. under gcc, avoid -fno-rtti std::type_index ti(typeid(*base)); if (ti == std::type_index(typeid(A))) { typemsg = "type A"; } else if (ti == std::type_index(typeid(B))) { typemsg = "type B"; } else { typemsg = "unknown"; } std::cout << typemsg << std::endl; // USING dynamic_cast // ====================== // needs RTTI. under gcc, avoid -fno-rtti if (dynamic_cast</*const*/ A*>(base)) { typemsg = "type A"; } else if (dynamic_cast</*const*/ B*>(base)) { typemsg = "type B"; } else { typemsg = "unknown"; } std::cout << typemsg << std::endl; } 

The program above prints this:

 type A type A type A 
0
Jul 10 '19 at 19:39
source share



All Articles