简体   繁体   中英

Check for derived type (C++)

How do I check at runtime if an object is of type ClassA or of derived type ClassB? In one case I have to handle both instances separately

ClassA* SomeClass::doSomething ( ClassA* )
{
    if( /* parameter is of type base class */) {

    } else if { /* derived class */ ) {

    }
}

Maybe I could say that the derived class ClassB has some special capabilities. But how do I do that without changing the existing class ClassA ?

It's generally a very bad idea to switch on the exact type like that. By doing this, you are tightly coupling your method to derived classes of ClassA . You should use polymorphism. Introduce a virtual method in class A, override it in class B and simply call it in your method.

Even if I was forced to handle the functionality in the external function itself for some reason, I would do something like:

class ClassA { 
  public: virtual bool hasSpecificFunctionality() { return false; }
};

class ClassB : public ClassA {
  public: virtual bool hasSpecificFunctionality() { return true; }
};

ClassA* SomeClass::doSomething ( ClassA* arg )
{
    if (arg->hasSpecificFunctionality()) {

    } else {

    }
}

Use a dynamic_cast as follows:

ClassA* SomeClass::doSomething(ClassA* a)
{
    if (dynamic_cast<DerivedClass*>(a)) {
        ...
    } else if (dynamic_cast<BaseClass*>(a)) {
        ...
    }
 }

dynamic_cast<T *>(ptr) will return 0 in case ptr is not a pointer of type T , and will return a pointer of type T otherwise.

dynamic_cast can usually be avoided and is an indicator of bad design / code. If you can avoid it, try to do so, as it requires RTTI in your final executable.

Why not have a doSomething() method on ClassB that handles ClassB's extra capabilities? This is the essence of polymorphism.

The syntax is this:

ClassA* SomeClass::doSomething ( ClassA* pa )
{
    ClassB* pb = dynamic_cast<ClassB*>(pa);
    if( pb ) ...

(Note that this only works within polymorphic class hierarchies. That is, there have to be virtual functions involved.)

However, you should try to avoid that. What do you need it for that cannot be solved by applying virtual functions?

Others have pointed out that switching on types is usually a bad idea, so I won't. If you really have to do it, you can use the typeid operator to switch on the dynamic type of an object:

ClassA* SomeClass::doSomething ( ClassA* a )
{
    if (typeid(*a) == typeid(ClassA)) {
        /* parameter is of type base class */
    } else if (typeid(*a) == typeid(ClassB)) {
        /* a specific derived class */ 
    } else {
        /* some other derived class */
    }
}

dynamic_cast is similar, but tests for convertibility, not equality:

ClassA* SomeClass::doSomething ( ClassA* a )
{
    if (ClassB *b = dynamic_cast<classB*>(a)) {
        /* parameter is, or is derived from, ClassB */
    } else {
        /* parameter is, or is derived from, ClassA but not ClassB */ 
    }
}

These only work if ClassA is polymorphic (that is, it has at least one virtual function).

Slighlty different that what you asked for

ClassB* b;
if ((b = dynamic_cast<ClassB*>(ptr)) == 0) {
    // not a classB*
} else {
    // a classB* in b
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM