dynamic_cast conversion
From cppreference.com
Safely converts pointers and references to classes up, down, and sideways along the inheritance hierarchy.
Contents |
[edit] Syntax
dynamic_cast < new_type > ( expression )
|
|||||||||
Returns a value of type new_type
or throws an exception.
[edit] Explanation
Only the following conversions can be done with dynamic_cast, except when such conversions would cast away constness or volatility.
1) If the type of expression is the exactly new_type or a less cv-qualified version of new_type, the result is expression.
2) If the value of expression is the null pointer value, the result is the null pointer value of type new_type
3) If new_type is a pointer or reference to
Base
, and the type of expression is a pointer or reference to Derived
, where Base
is a unique, accessible base class of Derived
, the result is a pointer or reference to the Base
class subobject within the Derived
object pointed or identified by expression. (note: implicit cast and static_cast can perform this conversion as well)
4) If expression is a pointer or reference to a polymorphic type, and
new_type
is a pointer to void, the result is a pointer to the most derived object pointed or referenced by expression.
5) If expression is a pointer or reference to a polymorphic type
Base
, and new_type
is a pointer or reference to the type Derived
a run-time check is performed:
a) The most derived object pointed/identified by expression is examined. If, in that object, expression points/referes to a public base of
Derived
, and if only one subobject of Derived
type is derived from the subobject pointed/identified by expression, then the result of the cast points/refers to that Derived
subobject. (this is known as the "downcast")
b) Otherwise, if expression points/refers to a public base of the most derived object, and, simultanously, the most derived object has an unambiguous public base class of type
Derived
, the result of the cast points/refers to that Derived
(this is known as the "sidecast")
c) Otherwise, the runtime check fails. If the dynamic_cast is used on pointers, the null pointer value of type new_type is returned. If it was used on references, the exception std::bad_cast is thrown.
6) When dynamic_cast is used in a constructor or a destructor (directly or indirectly), and expression refers to the object that's currently under construction/destruction, the object is considered to be the most derived object. If new_type is not a pointer or reference to the construction's/destructor's own class or one of its bases, the behavior is undefined.
Similar to other cast expressions, the result is:
- an lvalue if new_type is an lvalue reference type (expression must be an lvalue)
- an xvalue if new_type is an rvalue reference type (expression may be lvalue or rvalue)
- a prvalue otherwise (in this case, if new_type is a pointer type)
[edit] Note
Downcast can also be performed with static_cast, which avoids the cost of the runtime check, but it's only safe if the program can guarantee, through some other logic, that the object pointed to by expression is definitely Derived
.
[edit] Keywords
[edit] Example
#include <iostream> struct V { virtual void f() {}; // must be polymorphic to use runtime-checked dynamic_cast }; struct A : virtual V {}; struct B : virtual V { B(V* v, A* a) { // casts during construction dynamic_cast<B*>(v); // well-defined: v of type V*, V base of B, results in B* dynamic_cast<B*>(a); // undefined behavior: a has type A*, A not a base of B } }; struct D : A, B { D() : B((A*)this, this) { } }; struct Base { virtual ~Base() {} }; struct Derived: Base { virtual void name() {} }; int main() { D d; // the most derived object A& a = d; // upcast, dynamic_cast may be used, but unnecessary D& new_d = dynamic_cast<D&>(a); // downcast B& new_b = dynamic_cast<B&>(a); // sidecast Base* b1 = new Base; if(Derived* d = dynamic_cast<Derived*>(b1)) { std::cout << "downcast from b1 to d successful\n"; d->name(); // safe to call } Base* b2 = new Derived; if(Derived* d = dynamic_cast<Derived*>(b2)) { std::cout << "downcast from b2 to d successful\n"; d->name(); // safe to call } delete b1; delete b2; }
Output:
downcast from b2 to d successful