Search code examples
c++dynamic-caststatic-cast

static cast working and dynamic cast segfaults


The following code compiles and works fine:

#include<iostream>

class Base {
    protected:
        int _a;

    public: 
        virtual ~Base()=default;
        Base(int a) : _a{a} {};

        int getit() const { return _a; }
};

class Derived : public Base {
    public:

        Derived(int a) : Base{a} {};
        int get2() const { return 2*this->_a; }
};

int main() {
    Base D{2};
    auto* ptr = &D;
    auto* ptr2 = static_cast<Derived*>(ptr);


    std::cout << ptr2->get2() << std::endl;
}

OUTPUT

4

If I change the static_cast for a dynamic_cast it segfaults.

My question: Is it safe to use static_cast to cast down to derived classes that do not add any data members?


Solution

  • Is it safe to use static_cast to cast down to derived classes

    Only if the dynamic type of the object is the derived class (or the derived class is a base of the dynamic type that is even further derived). Casting upwards is also safe, but such conversion also works implicitly.

    If you don't know whether that's the case and - as in the example - when you know that isn't the case, this is absolutely not safe, and the behaviour of the example program is undefined. Using dynamic_cast is safe, but not checking whether it returns null, and then indirecting through that null isn't safe.

    In conclusion, this would be safe:

    if (auto* ptr2 = dynamic_cast<Derived*>(ptr)) {
        std::cout << ptr2->get2() << std::endl;
    } else {
        std::cout << "It's not Derived :(" << std::endl;
    }
    

    That said, if you think you need dynamic_cast, then you should probably reconsider the design. You should probably be using a virtual function instead. Example:

    class Base {
    protected:
        int _a;
    
    public: 
        virtual ~Base()=default;
        Base(int a) : _a{a} {};
    
        virtual int getit() const { return _a; }
    };
    
    class Derived : public Base {
    public:
        using Base::Base;
        int getit() const override { return 2*this->_a; }
    };