dynamic_cast is a runtime type conversion operator used in polymorphic inheritance hierarchies. It performs runtime type checking to ensure that a conversion is valid before it is applied.
- Commonly used for downcasting from a base class to a derived class.
- Requires the base class to have at least one virtual function.
- Indicates failed conversions through nullptr (for pointers) or std::bad_cast (for references).
#include <iostream>
using namespace std;
class Base{
public:
// Required for dynamic_cast
virtual void show() { }
};
class Derived : public Base {
public:
void display() {
cout << "Dynamic Cast Successful";
}
};
int main() {
Base* ptr = new Derived();
Derived* dptr = dynamic_cast<Derived*>(ptr);
if (dptr)
dptr->display();
delete ptr;
return 0;
}
Output
Dynamic Cast Successful
Explanation: dynamic_cast safely converts a base class pointer to a derived class pointer at runtime. If the conversion is valid, it returns the converted pointer; otherwise, it returns nullptr
Syntax
dynamic_cast<new_type>(expression)
Parameters
- new_type: Target type for the conversion.
- expression: Pointer or reference being converted.
Return Value
- Returns a valid pointer if the cast succeeds.
- Returns nullptr if a pointer cast fails.
- Throws std::bad_cast if a reference cast fails.
Note: dynamic_cast relies on Run-Time Type Information (RTTI), which introduces some runtime overhead. If a conversion is guaranteed to be valid, static_cast is generally more efficient.
Downcasting Using dynamic_cast
dynamic_cast is commonly used to safely convert a base class pointer to a derived class pointer.
#include <iostream>
using namespace std;
// Base Class declaration
class Base {
public:
virtual void print() {
cout << "Base" << endl;
}
};
// Derived1 class declaration
class Derived1 : public Base {
public:
void print() {
cout << "Derived1" << endl;
}
};
int main() {
Derived1 d1;
// Base class pointer holding
// Derived1 Class object
Base* bp = &d1;
// Dynamic_casting
Derived1* dp2 = dynamic_cast<Derived1*>(bp);
if (dp2 == nullptr)
cout << "Casting Failed" << endl;
else
cout << "Casting Successful" << endl;
return 0;
}
Output
Casting Successful
Explanation:
- bp is a base class pointer pointing to a Derived1 object.
- dynamic_cast checks the actual object type at runtime.
- Since the object is of type Derived1, the cast succeeds.
- A valid Derived1* pointer is returned.
Requirement for dynamic_cast
For downcasting to work, the base class must be polymorphic. A class becomes polymorphic when it contains at least one virtual function.
Example: Non-Polymorphic Base Class
#include <iostream>
using namespace std;
// Non-polymorphic base class
class Base {
public:
void print() {
cout << "Base" << endl;
}
};
class Derived1 : public Base {
public:
void print() {
cout << "Derived1" << endl;
}
};
int main() {
Derived1 d1;
Base* bp = &d1;
// Dynamic_casting
Derived1* dp2 = dynamic_cast<Derived1*>(bp);
if (dp2 == nullptr)
cout << "Casting Failed" << endl;
else
cout << "Casting Successful" << endl;
return 0;
}
Output
main.cpp: In function ‘int main()’:
main.cpp:24:21: error: cannot ‘dynamic_cast’ ‘bp’ (of type ‘class Base*’) to type ‘class Derived1*’ (source type is not polymorphic)
24 | Derived1* dp2 = dynamic_cast<Derived1*>(bp);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~
Explanation
- The base class does not contain any virtual function.
- Therefore, it is not polymorphic.
- RTTI information is unavailable.
- As a result, dynamic_cast cannot perform runtime type checking and compilation fails.
Invalid Downcasting
A cast fails when the actual object type does not match the target type.
#include <iostream>
using namespace std;
class Base {
virtual void print() {
cout << "Base" << endl;
}
};
// Derived1 class declaration
class Derived1 : public Base {
void print() {
cout << "Derived1" << endl;
}
};
// Derived2 class declaration
class Derived2 : public Base {
void print() {
cout << "Derived2" << endl;
}
};
int main() {
Derived1 d1;
Base* bp = &d1;
// Dynamic Casting
Derived2* dp2 = dynamic_cast<Derived2*>(bp);
if (dp2 == nullptr)
cout << "Casting Failed" << endl;
else
cout << "Casting Successful" << endl;
return 0;
}
Output
Casting Failed
Explanation
- bp points to a Derived1 object.
- The code attempts to convert it to Derived2*.
- Since the object is not of type Derived2, the conversion is invalid.
- dynamic_cast returns nullptr.
Downcasting References
When casting references, a failed conversion results in an exception instead of returning nullptr.
#include <exception>
#include <iostream>
using namespace std;
class Base {
virtual void print() {
cout << "Base" << endl;
}
};
class Derived1 : public Base {
void print() {
cout << "Derived1" << endl;
}
};
class Derived2 : public Base {
void print() {
cout << "Derived2" << endl;
}
};
int main() {
Derived1 d1;
Base* bp = dynamic_cast<Base*>(&d1);
// Type casting
Derived1* dp2 = dynamic_cast<Derived1*>(bp);
// Exception handling block
try {
Derived2& r1 = dynamic_cast<Derived2&>(d1);
}
catch (std::exception& e) {
cout << e.what() << endl;
}
return 0;
}
Output
main.cpp:31:15: warning: unused variable ‘dp2’ [-Wunused-variable]
31 | Derived1* dp2 = dynamic_cast<Derived1*>(bp);
| ^~~
std::bad_cast
Explanation
- d1 is an object of type Derived1.
- The code attempts to convert it to a Derived2 reference.
- The conversion is invalid because the object is not a Derived2.
- Since references cannot be nullptr, dynamic_cast throws a std::bad_cast exception.