Compiler will catch some of them, but not all. Here is an example of a disastrous cast:
#include <iostream>
#include <string>
using namespace std;
class A {
public:
A(std::string s, int x) : m_s(s), m_x(x) {}
void print() { cout << "A::print(): str = " << m_s << ", x = " << m_x << endl; }
private:
std::string m_s;
int m_x;
};
class B {
public:
B(int x) : m_x(x) {}
void print() { m_x++; cout << "B::print(): x = " << m_x << endl; }
private:
int m_x;
};
int main(int argc, char **argv) {
A *a = new A("abc", 1);
a->print();
B *b = (B*)a;
b->print();
a->print();
return 0;
}
Result on gcc (Ubuntu 5.4.0-6ubuntu1~16.04.4) 5.4.0 20160609:
A::print(): str = abc, x = 1
B::print(): x = 24828977
A::print(): str = bc, x = 1
Yes, we called B's methods on A's data, which means that our C-style cast worked as reinterpret_cast
. reinterpret_cast
just takes a memory region and allows you to treat is as something different. No seatbelts here.
On the other hand, if you try to compile something like this
A a;
B b;
a = (A)b;
return 0;
it will result in static_cast
and compile-time error. So C-style casting result depends on context.
This is NIGHTMARE when dealing with templates and auto
.
To avoid this problem, use static_cast
(for compile-time checks) and dynamic_cast
(for runtime checks) or reinterpret_cast
(for pointers and POD), clearly stating your intent.