Avoid type casting

Type casting, though dangerous and very uncontrolled, is occasionally necessary in C and C++; however, always question the need before you use it. There are three kinds of casts in C++:

A cast can change an object from one type to another. This includes casts between the built-in arithmetic types, and casts involving classes (not pointers to classes) or pointers to classes related by inheritance. These are fairly safe, because an actual conversion is taking place.

A cast that involves pointers and type coercion. This is the killer. The bit pattern of one type is interpreted as another type. This is very unsafe, and causes your code to die horribly (or worse, die subtly).

A runtime-checked cast takes the form dynamic_cast<type>(expression). At run time, if the type of the expression can be converted to type, you get that type; otherwise, you get 0 or an exception. Although this type of conversion is safe and can be very handy (for more dynamic dispatching and for optimizations), it is easy to abuse. Talk to your architect before using it.

Silent coercion

Unfortunately, some C++ constructs can be interpreted as either conversion or coercion. For example, a cast from one class pointer type to another is conversion if the two types are related by type inheritance, but coercion if they are not. The C++ compiler doesn't necessarily warn you if you intend the former but wind up with the latter. Worse still, a cast between pointers to member functions can be a conversion for the class, but a coercion for the function prototype.

Some types of casts are always coercion--for instance, casting a const or volatile pointer to one without those same attributes. If you make a member function const because it doesn't change the object semantics, you must cast your this pointer to non-const to make changes to the internal object state (unless your compiler supports mutable). Avoid this technique. Instead, overload the function or try another way (see "Concurrency and shared library issues" on page 129).

Casts to and from void* are dangerous, but in a fairly local way. Avoid such casts except where necessary. Do not use void* to avoid specifying a type for a variable or parameter. Use it only for manipulation of raw storage. (See "Avoid storage manipulation in open code" on page 128 for information about raw storage.)

Finally, although casts from a base class pointer to a derived class pointer are conversions (known as type narrowing), avoid them. If you accidentally specify types not related by inheritance, you silently get a coercion. This is also a poor programming technique and removes important information used for type checking. Templates in C++ and the Taligent Collection classes obviate the need for most such casts.

Cast operators

C++ now has a set of operators for performing casts. These operators remove the risk of unintended consequences for casting by making the programmer's intention explicit. However, they still don't make casting a good approach to a design. Very few compilers currently support these operators, but as they become widely available, use them as a safer alternative to old-style casts:

static_cast<target_type>(expression) performs a conversion from the type of the expression to the target type, if such a conversion is allowed. It never silently reinterprets bits as a different type.

const_cast<target_type>(expression) removes const and volatile modifiers. The target type must be the same as the type of the expression, except for const or volatile modifiers.

reinterpret_cast<target_type>(expression) coerces the expression to be the target type, without conversion. This is inherently unsafe and implementation dependent.

Summary

For a complete description of the casting operators, see an up-to-date C++ language reference.


[Contents] [Previous] [Next]
Click the icon to mail questions or corrections about this material to Taligent personnel.
Copyright©1995 Taligent,Inc. All rights reserved.

Generated with WebMaker