There’s More to Typecasting than C++ Cast Operators

xplicit typecasting is considered are an abomination in object-oriented programming. However, prudery won’t change the fact that casts are still a widely-used feature in C++ programming. Therefore, knowing exactly which typecasting operation is required for a given task and familiarity with the little known techniques that automate type conversions is essential even in state-of-the-art C++ projects.


You’ve been taught that explicit casts are denigrated and that they should be performed only by C++ cast operators. However, experience tells that static_cast, reinterpret_cast, and const_castare confusing, verbose and even dangerous.


Learn alternative cast techniques to simplify your code and eliminate repetitive cast expressions.

Presenting the Problem
When I introduced C++ cast operators more than six years ago, I truly wanted to believe that they were the right thing to use in through and through C++ programs. And yet, numerous questions from readers and my own experience have made me question C++ cast operators. This doesn’t mean that you should throw C++ cast operators out of the window. However, you should familiarize yourself with alternative cast techniques to produce better code.

Cast Away
In spite of the frowns with which C-style cast is often greeted, it’s a powerful and smart tool. The syntax is simple: enclose the target type in a pair of parentheses and place the argument after the parentheses. The following example casts a function pointerto long using C-style cast:

void myfunc(bool) {}void (*pf) (bool) = myfunc;long long val= (long long) myfunc;

Replacing C-style with C++ cast operators will put you in a dilemma?should you use static_cast or reinterpret_cast? The “recommended” solution is to start with static_castand see if it works:

long long val= static_cast (myfunc);

Notice how verbose and ugly this statement is compared to the elegance and compactness of C-style cast. But it get worse?this code doesn’t even compile. You need to use reinterpret_cast here, not static_cast:

long long val=  reinterpret_cast (myfunc); //ugly but works

No wonder why many C++ programmers give up static_cast entirely and stick to reinterpret_casteven when it’s wrong.

Unlike C++ cast operators, a single C-style cast expression can perform two different conversions at once as shown in the following example:

void func(unsigned char * data);//doesn't modify dataconst char txt[]="ABC";func ((unsigned char*) txt);//remove const, add unsigned

C++ pundits didn’t like this because the code is purportedly not explicit enough. However, using C++ cast notation makes the code extremely obfuscated, which doesn’t exactly make your code clearer or safer:

func (reinterpret_cast(const_cast(txt)));//remove const, add unsigned

Broad Cast
In applications that transmit data over networks or use persistent objects, casting an object to a char array and vice versa are common operations. Using reinterpret_castor C-style cast for every such conversion is tedious and messy. The infamous “union hack”, in spite of its bad reputation, can simplify this task by eliminating explicit cast expressions from your code.

Suppose you have a networking application that receives a variable of type double from a remote client. The variable is received as stream of bytes. Your task is to convert that char array to double, print its value and then store the value in a file. In other words, you need to cast a char array to double and then cast the result back to a char array. The easiest way to do that is to define a union that contains two members; the first member is of type double and the second one is an array of sizeof(double)char:

#include using namespace std;union hack {//both members overlap exactly   double d; char bytes[sizeof(double)];} h;char * getbytes(size_t sz); //reads client datah.d= *(double*) getbytes(sizeof(double));cout<<"received the value: "<

To reconstitute the original double value from the file values.dat, use the union like this:

ifstream archive("values.dat");archive.read(h.bytes, sizeof (h.d));cout<<"retrieved value: "<

In simpler words, the union allows you to view the same piece of memory either as a double or as a char array simply by switching between the two union members. Recall that all union members have the same address. To ensure that they also occupy exactly the same number of bytes, calculate the size of the char array using sizeof(type_of_first_member). The union hack eliminates the drudgery of using reinterpret_castin every I/O operation. Notice that the code doesn't use a single cast expression.

Obviously, the next evolutionary step is to replace the union with a union template, thus automating the conversion from an arbitrary type Tto a char array:

template  union hack                {  T data;  char bytes[sizeof(T)] ;};

Dare to Be Different
Bad PR and snobbery shouldn't deter you from using features that get the job done quickly, elegantly and often with less bugs and hesitation as witnessed with C++ cast operators. C-style cast has three advantages over C++ style cast:

    • It's less verbose.
  • It frees you from the confusion between static_cast and reinterpret_cast.
  • It can perform two cast operations in a single expression.

The union hack eliminates the clutter and inelegance of recurrent cast expressions.

Share the Post:
Share on facebook
Share on twitter
Share on linkedin

Overview

Recent Articles:

©2023 Copyright DevX - All Rights Reserved. Registration or use of this site constitutes acceptance of our Terms of Service and Privacy Policy.

Sitemap