[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-devel
Subject:    Casts (was: Re: Strange effect...)
From:       Johannes Sixt <Johannes.Sixt () telecom ! at>
Date:       1997-12-23 18:32:00
[Download RAW message or body]

On Tue, 23 Dec 1997, Prasanth Kumar wrote:
>Johannes Sixt wrote:
><snip>
>> Casts are a hack. Always. Well, almost always.
>> 
>> If you really want to do it with casts, then do it the C++ way:
>> 
>> printf("A -> %s\n\n", static_cast<const char *>(A));
>> 
>> C-style casts are a hack in C++. Always. Really.
>> 
>> -- Hannes
>
>I am not familiar with the new C++ way of doing casts but...
>what is the new way not a hack compared to the C-style?

C++ introduces four new operators that do type casts:

static_cast
const_cast
reinterpret_cast
dynamic_cast

as well as a functional notation for type conversion.

The differences are:
- they are safer because you can't cast anything to everything,
- it's more obvious which cast is intended,
- you can search the source file for casts (have you ever tried to search for
C-style casts?),
- they are more powerful.

A const_cast  can be used to remove const specifiers from pointers:

void f(const T* pct) {
    T* pt = const_cast<T*>(pct);
}

It works also for references, but it can't perform other casts.

A static_cast basically can do only casts from type T1 to T2 where
there's an implicit cast from T2 to T1:

struct B { int i; };
struct D : B {};
D d;
B* pb = &d;        // implicit cast D* -> B*
D* pd = static_cast<D*>(pb);   // cast needed: B* -> D*

Note that static_cast can't be used for unrelated pointer types:

int* pi = static_cast<int*>(pb); // error since int* and B* are unrelated

The following would work, however, because pointers can be cast to void*:

int* pi = static_cast<int*>(static_cast<void*>(pb));

but it disregards alignment restrictions.

A reinterpret_cast does what it's name suggests: it reinterprets values:

int* pi = reinterpret_cast<int*>(errno);

Most conversions that can be done with reinterpret_cast have defined behavior
only if the value is converted back with a reinterpret_cast to the original
type. The intent is that the result of a reinterpret_cast is "unsurprising to
those how know the addressing structure of the underlying machine."

A dynamic_cast is like a static_cast which does runtime-typechecking:

struct B { };
struct D : B {};
D d;
B* pb = &d;
dynamic_cast<D*>(pb);   // returns pointer to d
B b;
pb = &b;
dynamic_cast<D*>(pb);   // returns NULL, since pb doesn't point to a D

dynamic_cast obviously requires runtime type information.

The functional notation of cast is just a different syntax for C-Style casts:

enum E { e1, e2, e3 };
E err = E(errno);               // equivalent to (E) errno
int pi100 = int(100.0*3.14159);

Looks like a constructor call, doesn't it?

Finally, the semantics of a C-style cast is the first of:

- a const_cast,
- a static_cast,
- a static_cast, followed by a const_cast,
- a reinterpret_cast,
- a reinterpret_cast, followed by a const_cast

that would work.

-- Hannes

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic