Precisely, why does B b = (B&) a
compile and work whereas B b = (B) a
does not in the below program?
#include <iostream>
using namespace std;
class A {public: void f(){ cout<<"A"<<endl;} };
class B : public A { public: void f(){cout<<"B"<<endl;} };
void g(A a){ B b = (B&) a; b.f(); }
int main() {
B b; g(b);
return 0;
}
Is there something about casting to a derived type with reference that I am missing here ? If I just cast to B, it gives a compile time error that the constructor B(A a) does not exist.
Because the implicit conversion from A
to B
doesn't exist, and you didn't define an explicit one either.
Reference casting, on the other hand, is valid because it is allowed for inherited types. More precisely, you can cast both ways between different classes in the same inheritance hierarchy. Same goes for pointers. The related concept is called polymorphism, if you'd like some pointers for further study.
Do note, however, that it only makes sense for an object that is of type B
to be cast to B
. E. g.:
B b;
A& aRef = B; // equivalent of A& ref = (A&)B;
B& bRef = (B&)aRef;
What you did will fail at runtime as soon as you try to access some data or method of B
that does not exist in A
. Because your actual object is A
, not B
.
Upcasting (from an descendant to an ascendant) is always safe because any object of a class that inherits the base class is a valid base object. The downcasting, however, is dangerous for the exact reason I explained above, and should never be done using a C-style cast. Instead, use dynamic_cast
:
B b;
A& aRef = B;
B& bRef = dynamic_cast<B&>(aRef);
dynamic_cast
uses RTTI (run-time type information) to validate the operation and will throw an std::bad_cast
exception if the conversion is not valid. This is unlike dynamic_cast
ing pointers, in which case the cast returns nullptr
instead of throwing an exception.