c++inheritancertti

Check intermediate ancestor type of object


Some places in our code make extensive use of 'dynamic_cast` do check the type of a given object:

    if (dynamic_cast<Foo*>(bar))
        return "foo";
    else
        return "not-foo";

In some specific section of the code, we decided to switch to typeid, but we ran into a problem: we're checking an object against an arbitrary ancestor, not to its concrete type:

#include <typeinfo>
#include <iostream>

struct Base
{
    virtual ~Base() {} // enable vtable
};

struct Derived : Base{};

struct DerivedAgain : Derived{};
struct OtherDerived : Derived{};

int main() {
    Base* b = new DerivedAgain;
    // if (typeid(*b) == typeid(Derived)) // will print false
    if (dynamic_cast<Derived*>(b))
        std::cout << "true\n";
    else
        std::cout << "false\n";

    return 0;
}

Is there a way to check if b is Derived* without dynamic_cast?

P.S.: I'm aware this might be indicative of some larger problem with the design of the code, but I want to know specifically how to make this kind of check.


Solution

  • It seems that dynamic_cast is what I want in this specific case, since it is the only thing in the language that will actually examine the dependency chain of the object.


    That said, it's worth mentioning that, as I said in the question and many people said in the comments, having to use dynamic_cast may be an indicative of a larger design problem in the code. One possible solution is using a polymorphic method instead:

    // with checking
    int doThing(Base* b)
    {
        if (auto d = dynamic_cast<Derived*>(b))
            return stuff(d);
        if (auto d = dynamic_cast<OtherDerived*>(b))
            return otherStuff(d);
    
        return 0;
    }
    
    // with polymorphism
    int doThing(Base* b)
    {
        return b->stuff();
    }
    
    // stuff is a virtual method defined in Base, Derived and OtherDerived
    struct Base
    {
        virtual int stuff() const {}
    };
    
    struct Derived : Base
    {
        int stuff() const override { return stuff(this); }
    };
    
    struct OtherDerived : Base
    {
        int stuff() const override { return otherStuff(this); }
    };