Reputation: 978
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?
Upvotes: 1
Views: 457
Reputation: 238381
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; }
};
Upvotes: 7
Reputation: 51845
This is a case where using the wrong type of cast is causing you grief. As mentioned in the comments, ptr2
is not pointing to a valid Derived
object.
So, with your static_cast
, you are seeing undefined behaviour; this just happens to give an apparently 'correct' answer, but you can never rely on that.
However, using a dynamic_cast
will result in ptr2
having a nullptr
value (because the object pointed to by ptr
is not a Derived
); your attempt to dereference that nullptr
is causing your program to crash (as it most often will).
But note that using the dynamic_cast
will allow you to readily check if that cast succeeded (by testing the returned value for nullptr
); the static_cast
doesn't give you that option.
Upvotes: 1