C++. Operators dynamic_cast, const_cast, reinterpret_cast, static_cast

Dynamic identification of types. Operators dynamic_cast, const_cast, reinterpret_cast, static_cast. Examples


Contents


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