Dynamic identification of types. Operators dynamic_cast, const_cast, reinterpret_cast, static_cast. Examples
Contents
- 1. Operator dynamic_cast. Example
- 2. Replacing the typeid operator with a dynamic_cast operator
- 3. Operator const_cast. Example
- 4. Operator reinterpret_cast. Example
- 5. Operator static_cast. Example
- Related topics
Search other resources:
1. Operator dynamic_cast. Example
The dynamic_cast operator is used to dynamically cast a type while checking the correctness of the cast. If the cast cannot be performed, then it fails and the operator returns nullptr.
The general form of the dynamic_cast operator is as follows
dynamic_cast<type> (expression);
here
- type – the resulting type;
- expression – an expression that is cast to type.
The dynamic_cast operator is effective in the case of casting types that form an inheritance hierarchy (polymorphic types). If the dynamic_cast operator is applied to pointers, a null pointer (nullptr) is returned. If this operator is applied to references, a bad_cast exception is thrown in case of an error.
Example.
The example shows the use of the dynamic_cast operator for two classes A and B that form an inheritance hierarchy. Various situations of using the operator are considered.
#include <iostream> #include <typeinfo> using namespace std; // The dynamic_cast<> operator - determines whether types can be cast dynamically // Base class class A { public: virtual void Show() { cout << "A::Show()" << endl; } }; // Inherited class class B :public A { public: void Show() { cout << "B::Show()" << endl; } }; void main(void) { // 1. Declare variables A* pA; // pointer to the base class B* pB; // pointer to derived class A a; B b; // 2. Use pointer pA pA = &a; // Ok pA->Show(); // It is also possible, a pointer to a base class can point to an instance of a derived class. pA = &b; pA->Show(); // 3. Use the pointer pB // It cannot be done that way. // pB = &a; // forbidden, the base class cannot be extended to a derived class // 4. Using the dynamic_cast operator. // Case: pointer gets the address of a class instance cout << "dynamic_cast<type*>(&obj): " << endl; // 4.1. Cast B* <= A* with check pB = dynamic_cast<B*> (&a); // it is forbidden, pB = nullptr if (pB==nullptr) cout << "Cast A* <= B* -> Error" << endl; // this option else cout << "Cast A* <= B* -> Ok" << endl; // 4.2. Cast B* <= B* pB = dynamic_cast<B*> (&b); // it is allowed if (pB != nullptr) cout << "Cast B* <= B* -> Ok" << endl; // this option else cout << "Cast B* <= B* -> Error" << endl; // 4.3. Cast A* <= A* pA = dynamic_cast<A*>(&a); // it is allowed, pA!=nullptr if (pA != nullptr) cout << "Cast A* <= A* -> Ok" << endl; else cout << "Cast A* <= A* -> Error"; // 4.4. Cast A* <= B* pA = dynamic_cast<B*>(&b); // it is allowed if (pA) cout << "Cast A* <= B* -> Ok" << endl; else cout << "Cast A* <= B* -> Error"; cout << "---------------------------------" << endl; // 5. Using the dynamic_cast operator. // Case: pointer gets address of another pointer cout << "dynamic_cast<type*>(ptr -> Type): " << endl; // 5.1. Cast B* <= B* // Pointer pA refers to the object of class B pA = &b; // можно, pA->b pB = dynamic_cast<B*>(pA); // you can, because pA refers to an object of class B if (pB) cout << "Cast B* <= (pA -> B) --> Ok " << endl; // + else cout << "Cast B* <= (pA -> B) --> Error " << endl; // 5.2. Cast B* <= A* // Pointer pA refers to an object of class A pA = &a; // pA -> A pB = dynamic_cast<B*>(pA); // not possible, because pA refers to an object of class A if (pB) cout << "Cast B* <= (pA -> A) --> Ok " << endl; else cout << "Cast B* <= (pA -> A) --> Error " << endl; // + // 5.3. Cast A* <= B* // The pB pointer points to an object of class B pB = &b; pA = dynamic_cast<A*> (pB); // it is allowed if (pA) cout << "Cast A* <= (pB -> B) --> Ok " << endl; else cout << "Cast A* <= (pB -> B) --> Error" << endl; // 5.4. Cast A* <= A* // pB = &a; // compilation error }
Program result
A::Show() B::Show() dynamic_cast<type*>(&obj): Cast A* <= B* -> Error Cast B* <= B* -> Ok Cast A* <= A* -> Ok Cast A* <= B* -> Ok --------------------------------- dynamic_cast<type*>(ptr -> Type): Cast B* <= (pA -> B) --> Ok Cast B* <= (pA -> A) --> Error Cast A* <= (pB -> B) --> Ok
⇑
2. Replacing the typeid operator with a dynamic_cast operator
If the classes form a hierarchy (classes are polymorphic), then the typeid operator can be replaced by the dynamic_cast operator.
The example below shows this feature.
#include <iostream> #include <typeinfo> using namespace std; // replacing the typeid operator with a dynamic_cast operator class A { public: virtual void Show() { cout << "A::Show()" << endl; } }; class B :public A { public: void Show() { cout << "B::Show()" << endl; } }; void main(void) { // 1. Declaring pointers and class objects A* pA; // pointer to base class B* pB; // pointer to derived class A a; B b; // 2. Using the typeid operator cout << "typeid:" << endl; // 2.1. pA->A pA = &a; if (typeid(*pA) == typeid(B)) // Is it possible to cast *pA to type B? { pB = (B*)pA; cout << "Cast B <= (pA->A) --> OK" << endl; } else cout << "Cast B <= (pA->A) --> Error" << endl; // 2.2. pA->B pA = &b; if (typeid(*pA) == typeid(B)) // Is it possible to cast *pA to type B? { pB = (B*)pA; cout << "Cast B <= (pA->B) --> OK" << endl; } else cout << "Cast B <= (pA->B) --> Error" << endl; // 3. Using the dynamic_cast operator cout << "-----------------------------------" << endl; cout << "dynamic_cast: " << endl; // 3.1. pA->A pA = &a; pB = dynamic_cast<B*> (pA); if (pB) cout << "Cast B* <= (pA->A) --> OK" << endl; else cout << "Cast B* <= (pA->A) --> Error" << endl; // 3.2. pA->B pA = &b; pB = dynamic_cast<B*> (pA); if (pB) cout << "Cast B* <= (pA->B) --> OK" << endl; else cout << "Cast B* <= (pA->Error) --> Error" << endl; }
Program result
typeid: Cast B <= (pA->A) --> Error Cast B <= (pA->B) --> OK ----------------------------------- dynamic_cast: Cast B* <= (pA->A) --> Error Cast B* <= (pA->B) --> OK
⇑
3. Operator const_cast. Example
The const_cast operator is used to replace the const modifier and/or the volatile modifier. In this operator, the type of the result must match the original one. The const_cast operator is used to get rid of the const modifier.
The general form of the const_cast operator is as follows
const_cast<type> (expr)
Example.
Using the const_cast operator through a reference to a constant value, you can remove the const modifier from this constant value.
#include <iostream> using namespace std; // 1. Using a const_cast for a reference void ExampleConstCast1(const int& value) { // remove const specifier, access value int& ref = const_cast<int&> (value); ref = 20; // through a reference to a constant value, you can access value // value = 50; - not allowed, expression must be a modifiable lvalue } // 2. Using const_cast for a reference void ExampleConstCast2(const int& value) { // remove the const modifier from the value const_cast<int&> (value) = value + value; } // 3. Applying const_cast to a pointer void ExampleConstCast3(const int* x) { int* p = const_cast<int*> (x); // remove const from x *p = 100; } void main() { // Demonstration of using the const_cast modifier int t = 30; ExampleConstCast1(t); cout << "t = " << t << endl; // t = 20 ExampleConstCast2(t); cout << "t+t = " << t << endl; // t = 20+20 = 40 int x = 50; ExampleConstCast3(&x); cout << "x = " << x << endl; // x = 100 }
Program result
t = 20 t+t = 40 x = 100
⇑
4. Operator reinterpret_cast. Example
The reinterpret_cast operator is designed to convert one type to another, even a non-compatible type. This operator can also be applied to pointers of any type.
General form
reinterpret_cast<type> (expr)
where
- type – resulting type;
- expr – an expression that is cast to a new type.
Example.
#include <iostream> using namespace std; void main() { // 1. Convert char* => int int number; const char* pStr = "Hello world!"; // get a pointer to str as an integer number = reinterpret_cast<int> (pStr); cout << "number = " << number << endl; // 2. Convert int => double*, // convert integer to pointer unsigned int num = 300; double* p; p = reinterpret_cast<double*> (num); cout << "p = " << p << endl; }
Program result
number = 9476928 p = 0000012C
⇑
5. Operator static_cast. Example
The static_cast operator is used to perform a non-polymorphic cast without checking for its correctness. The cast type and the resulting type can be such that they do not form an inheritance hierarchy.
The general form of the operator is as follows
static_cast<type> (expr)
here
- type – resulting type;
- expr – an expression that is cast to type.
Example.
#include <iostream> using namespace std; void main() { // The use of the static_cast operator is a non-polymorphic cast, // used in the same way as the normal cast operator // 1. Convert int => double double x; int a = 25; x = static_cast<double> (a) / 4; cout << "x = " << x << endl; // x = 6.25 // 2. Convert double => char double z = 51.55; char c = static_cast<char> (z); // c = '3' cout << "c = " << c << endl; // 3. Convert double => short short s = static_cast<short>(118.232); cout << "s = " << s << endl; // s = 118 }
Program result
x = 6.25 c = 3 s = 118
⇑
Related topics
⇑