Why is the type w_char introduced in C ++

For a long time there was only one cast operator in C and C ++, also known in detail as Typecast. You write the desired data type in brackets in front of the variable and this enables an assignment to a variable of the desired type.

The example is a pure C example. The function malloc () takes care of memory and returns an untyped void pointer. In C we need a for this #include , in C ++ this becomes #include

#include void example () {void * poi = malloc (400); // int * intpoi = poi; // NOK: invalid conversion from 'void *' to 'int *' int * intpoi = (int *) poi; // OK }

If we understand the int pointer as a pointer to an int array, it is nicer to create it constantly. You can do that by const is used accordingly, but the compiler does not allow casting to an array type directly.

#include void example () {void * poi = malloc (400); // int intarr [] = (int []) poi; // NOK: ISO C ++ forbids casting to an array type int * const intarr = (int * const) poi; //OK }

You don't need a cast for the following situation.

void example () {double dou = 42.84; int i = dou; cout << i << endl; // 42}

Despite the loss of data, a C / C ++ compiler brings at most one warning depending on the setting. you can also add a cast for clarification.

void example () {double dou = 42.84; int i = (int) dou; cout << i << endl; // 42}

The classic cast is a very powerful cast, you can cast practically anything to anything that can do a lot of damage. Here is a drastic example.

void dangerous () {int x = 123; char * charpoi = (char *) x; cout << charpoi << endl; // Runtime error }

Here the int value is interpreted as a memory address to which a char pointer points. cout then tries to read out a zero-terminated C string from this address ...


The 4 additional casts in C ++

In order to make code safer, more readable and maintainable, new cast forms were introduced in C ++ 4 that cover different applications.

  • const_cast (expression)
  • static_cast (expression)
  • reinterpret_cast (expression)
  • dynamic_cast (expression)

The order is roughly from weak to strong, const_cast and static_cast are considered weak casts, and the last two are considered strong casts. The strongest cast is still the old C cast.


const_cast (variable)

The const_cast only allows assignment to the same data type, which is not a const type. It can only be used for pointer and reference types. In these cases, however, it is powerful, because after casting, the variable is no longer constant. The classic C-String, which cannot be changed even after using const_cast, plays a special role here. The following examples show the behavior.

With int pointer

void const_cast () {int a = 42; const int * poi = & a; // * poi = 43; // assignment of read-only location '* poi' // int * poi2 = poi; // invalid conversion from 'const int *' to 'int *' int * poi2 = const_cast (poi); * poi2 = 43; cout << * poi2 << endl; // 43}

With char pointer

void const_cast () {char ch = 42; const char * cpoi = & ch; char * cpoi2 = const_cast (cpoi); * cpoi2 = 65; // OK cout << * cpoi2 << endl; // A}

With C-String (special role of C-Strings)

void const_cast () {const char * cs = "Hello"; char * cs2 = const_cast (cs); // * cs2 = 'h'; // Build ok, but runtime error}

"Hello" is stored in the data section in a string pool. If another C-string "Hello" is created, no new memory is acquired, just a new pointer.

With class pointer

class X {public: int z; }; void const_cast () {X x; const X * xpoi = & x; // xpoi-> z = 17; // assignment of member 'X :: z' in read-only object X * xpoi2 = const_cast (xpoi); xpoi2-> z = 17; cout << xpoi2-> z << endl; }

With char reference

void const_cast () {char cha = 42; const char & ref = cha; // ref = 65; // assignment of read-only reference 'ref' char & ref2 = const_cast (ref); ref2 = 65; // OK cout << ref2 << endl; // A}

With reference to C-String

void const_cast () {const char * cs = "Hello"; const char * & cref = cs; char * & cref2 = const_cast (cref); // * cref2 = 'h'; // Build OK, but runtime error}

With class reference

class X {public: int z; }; void const_cast () {X x; const X? xref = x; //xref.z = 17; // assignment of member 'X :: z' in read-only object X & xref2 = const_cast (xref); xref2.z = 17; cout << xref2.z << endl; }

This cast is necessary when passing const variables to functions that do not have a const parameter in the parameter list.

void const_cast_demo () {const char * cstr = "Hello"; // no_const_param (cstr); // NOK: invalid conversion from 'const char *' to 'char *' no_const_param (const_cast (cstr)); // OK} void no_const_param (char * cstr) {cout << cstr << endl; }

static_cast (variable)

static_cast allows the conversion of related data types. It can be used, for example, to make a conversion with data loss clear. A conversion from about double to int delivers at most one warning in a C / C ++ compiler. To make such situations clearer, one can and should one static_cast use.

Optional use of static_cast.

void static_cast () {double dou = 42.84; int i = static_cast & ltint> (dou); cout << i << endl; // 42}

It is more interesting that static_cast can also be used with related pointer types. In such cases it is necessary.

Casting a void pointer to a typed pointer (cast required)

void static_cast () {void * voidpoi = malloc (400); int * intpoi = static_cast (voidpoi); // OK int * const intarr = static_cast (voidpoi); //OK }

The void pointer can be cast to any other pointer type using the static_cast.

No cast is required for the opposite direction.

void static_cast () {int x = 123; int * intpoi = & x; void * voidpoi = intpoi; // no cast required}

However, static_cast cannot be used for pointers with different typefaces.

void static_cast () {int y = 42; int * intpoi = & y; // char * charpoi = static_cast (intpoi); // NOK: invalid static_cast from type 'int *' to type 'char *' char ch2 = 'A'; char * charpoi = & ch2; // int * intpoi2 = static_cast (charpoi); // NOK: invalid static_cast from type 'char *' to type 'int *'}

However, if you insert a void pointer in between you can bypass this restriction.

In the following code snippet you get memory for seven int variables and then use this memory to store char variables.

void static_cast () {int * intarr = new int [7]; // heap void * vpoi = intarr; char * chararr = static_cast (vpoi); // now you have a char array of length sizeof (int) * 7 = 28 (if an int has 4 bytes) for (int i = 0; i <27; i ++) chararr [i] = 97 + i; chararr [27] = 0; // stringent cout << chararr << endl; }

static_cast for related class types.

class Parent {}; class Child1: public Parent {}; class Child2: public Parent {}; void static_cast () {Child1 child1; Parent * ppoi = & child1; Child1 * childpoi = static_cast (ppoi); }

A static_cast from Child1 to Child2 is not possible (for good reason).


reinterpret_cast (variable)

With this cast you can "forcibly" change the data type of a variable. You have to be careful with this instrument.

void reinterpret_cast_demo_1 () {// Put a char pointer as an integer int x = reinterpret_cast (poi); // OK cout << "poi =" << poi << endl; cout << "vpoi =" << vpoi << endl; cout << "x =" << x << endl; }

The reverse is not recommended.

void reinterpret_cast_demo_2 () {// Put an int as char * on int y = 43; char * cpoi = reinterpret_cast (y); // Build OK, but ... cout << "cpoi =" << cpoi << endl; // Runtime error }

dynamic_cast (variable)

The dynamic_cast can only be used on pointers or references. In addition, the type to be cast must be polymorphic, i.e. the associated class has (at least) one virtual method. It is enough z. E.g. the destructor, the method can also be public, protected or private.

A dynamic_cast uses RTTI (Run-Time Type Information) in the background to get information at runtime. Most compilers use RTTI as the default. If not, you have to set the compiler switch manually.

The VMT (virtual method table) is used to check whether the cast can be carried out or not.

Is it a non-convertible Pointer so delivers dynamic_cast one Null pointer.
Is it a non-convertible Reference thus creates an exception of type bad_cast thrown.

An example with references

void dynamic_cast_mit_references () {Base base; Derived the; Base? Bref = base; Derived & dref = der; bref = dref; // no cast necessary, but possible bref = dynamic_cast (dref); // dynamic_cast requires round brackets try {// Derived & der2 = base; // cannot convert Base to Derived & Derived & der2 = dynamic_cast (base); // no compiler error but exception bad_cast is thrown} catch (bad_cast ex) {cout << ex.what () << endl; // Bad dynamic_cast! }}