Search code examples
c++classinheritancepolymorphismlanguage-lawyer

Can dynamic_cast<Derived*>(static_cast<Base*>(voidPtr)) ever go wrong if voidPtr is null pointer or pointing to object that is inherited from Base?


class Base {
    // ...
};

class Derived : public Base {
    // ...
};

class OtherDerived : public Base {
    // ...
};

If I know for a fact that voidPtr of type void* is a null pointer or pointing to an object of Derived or OtherDerived. Can dynamic_cast<Derived*>(static_cast<Base*>(voidPtr)) return non-null pointer if voidPtr is pointing to an object of type OtherDerived

void someFunction(void* voidPtr) {
  auto derived = dynamic_cast<Derived*>(static_cast<Base*>(voidPtr));
  if (derived == nullptr) {
    return;
  }

  // do something with derived
}

I came across with this problem when I was using Qt and its void *QVariant::data() function.


Solution

  • Can dynamic_cast<Derived*>(static_cast<Base*>(voidPtr)) ever go wrong if voidPtr is null pointer or pointing to object that is inherited from Base?

    No, it will return nullptr or a pointer to a Derived. Only if voidPtr is not nullptr and is not actually pointing at a Base will there be problems (undefined behavior). Therefore, you must cast the Derived* to Base* in the call to someFunction.

    Undefined behavior example:

    #include <iostream>
    
    class Base {
    public:
        virtual ~Base() = default;
    };
    
    class Derived : public Base {};
    class OtherDerived : public Base {};
    
    void someFunction(void* voidPtr) {
        // Undefined behavior:
        auto derived = dynamic_cast<Derived*>(static_cast<Base*>(voidPtr));
    
        if (derived == nullptr) {
            std::cout << "fail\n";
            return;
        }
        // do something with derived
    }
    
    int main() {
        auto d = new Derived;
        someFunction(d); // should be `someFunction(static_cast<Base*>(d));`
        delete d;
    }
    

    Can dynamic_cast<Derived*>(static_cast<Base*>(voidPtr)) return non-null pointer if voidPtr is pointing to an object of type OtherDerived

    No, not with the inheritance as you've defined it.