Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Casts: What are the differences?

2 views
Skip to first unread message

Dr. Richard Botting

unread,
Feb 26, 1997, 3:00:00 AM2/26/97
to

I'm feeling like I'm lost in twisty maze of little passages
that all look alike.... Or was it a maze of little twisty passages
that all look alike?

In the December Draft/HTML Version I find:

5.2.7 Dynamic cast [expr.dynamic.cast]
1 The result of the expression dynamic_cast<T>(v) is the result of con-
verting the expression v to type T. T shall be a pointer or reference
to a complete class type, or "pointer to cv void". Types shall not be
defined in a dynamic_cast. The dynamic_cast operator shall not cast
away constness (_expr.const.cast_).

5.2.9 Static cast [expr.static.cast]
1 The result of the expression static_cast<T>(v) is the result of con-
verting the expression v to type T. If T is a reference type, the
result is an lvalue; otherwise, the result is an rvalue. Types shall
not be defined in a static_cast. The static_cast operator shall not
cast away constness (_expr.const.cast_).

5.4 Explicit type conversion (cast notation) [expr.cast]
1 The result of the expression (T) cast-expression is of type T. The
result is an lvalue if T is a reference type, otherwise the result is
an rvalue.

I looked in my C++.FAQ but they didn't help too much.

I could do with a simple briefing describing the differences between
a cast
a constant cast
a static cast
a dynamic cast
a reinterpret cast

--
dick botting http://www.csci.csusb.edu/dick/signature.html
Disclaimer: CSUSB may or may not agree with this message.
Copyright(1997): Copy freely but say where it came from.
I have nothing to sell, and I'm giving it away.
---
[ comp.std.c++ is moderated. To submit articles: try just posting with ]
[ your news-reader. If that fails, use mailto:std...@ncar.ucar.edu ]
[ FAQ: http://reality.sgi.com/employees/austern_mti/std-c++/faq.html ]
[ Policy: http://reality.sgi.com/employees/austern_mti/std-c++/policy.html ]
[ Comments? mailto:std-c++...@ncar.ucar.edu ]

Steve Clamage

unread,
Feb 26, 1997, 3:00:00 AM2/26/97
to

In article c...@news.csus.edu, di...@silicon.csci.csusb.edu (Dr. Richard Botting) writes:
>I'm feeling like I'm lost in twisty maze of little passages
>that all look alike.... Or was it a maze of little twisty passages
>that all look alike?
>
>In the December Draft/HTML Version I find: ...

>
>I could do with a simple briefing describing the differences between
> a cast
> a constant cast
> a static cast
> a dynamic cast
> a reinterpret cast

I deleted the quotes from the draft, which were the introductory
paragraph describing each kind of cast. The introductory paragraphs
are (intentionally) nearly identical. The remainder of each section
describes its cast in detail.

The draft standard uses 7 pages to describe all the casts. I don't
think a complete explanation could be much smaller, so I'll use
the pedagogical device of oversimplification to keep things down
to the size of a netnews article. First I'll provide a brief
rationale for introducing the four new casts.

The old-style cast could be used for several different purposes. In
particular, it was commonly used for
- changing constness: (char*)ptr_to_const_char
- converting a value to a value of a different type: (int)floating_value
- navigating a hierarchy: (derived*)ptr_to_base
- type "punning": (int*)ptr_to_void
(Type punning generally means treating an object, particularly a
pointer, as an object of a different type.)

When the notations (T)e and T(e) are both allowed, they are exactly
equivalent. Sometimes only one of the notations is allowed.

When you see a cast expression like "(T)(expr)" it is often hard to
tell why the cast is there. Also, it isz often hard to tell whether
the cast is likely to be dangerous or nonportable. Finally, there is
no way to scan a source file and reliably find every cast, unless you
have a "smart editor" that can fully parse C++ source code.

C++ introduced four new cast operators to address those problems: Each
cast is intended for a particular purpose (although there is some
overlap), and each cast uses a new keyword that can be found easily
with any text editor.

Here is an oversimplified description of each cast. In particular,
I'm ignoring references and discussions of lvalue vs rvalue.
(Generally speaking, what is true for pointers is true for references.
Generally speaking, casting yields an rvalue, except that casting
a reference generally yields an lvalue.)

static_cast: primarily for value conversion
- can perform any conversion which is allowed implicitly
- can reverse any implicit conversion except cannot downcast from a
virtual base class
- cannot remove constness

dynamic_cast: primarily for hierarchy navigation
- can upcast a ptr_to_derived to any of its unambiguous base classes
- can downcast a ptr_to_base (including virtual base classes) to any
unambiguous derived class if the class is polymorphic. Indicates
failure if the object isn't really the right type.
- can cast "sideways" in a hierarchy if the class is polymorphic
- cannot remove constness

reinterpret_cast: primarily for type punning
- can convert pointers to integer types and vice versa
- can convert a pointer to an unrelated pointer type
- results are implementation-defined and might not work
- cannot remove constness

const_cast: primarily to remove constness
- can change the const and volatile specifiers of a type
- cannot otherwise change the type

The old-style cast is now defined as a static_cast or reinterpret_cast
possibly followed by a const_cast. (The only dynamic_casts that an
old-style cast can perform can also be performed by a static_cast.
If an old-style cast could be performed by both a static_cast and a
reinterpret_cast, the static_cast interpretation is chosen.)

---
Steve Clamage, stephen...@eng.sun.com
---
[ comp.std.c++ is moderated. To submit articles: Try just posting with your
newsreader. If that fails, use mailto:std...@ncar.ucar.edu
comp.std.c++ FAQ: http://reality.sgi.com/austern/std-c++/faq.html
Moderation policy: http://reality.sgi.com/austern/std-c++/policy.html
Comments? mailto:std-c++...@ncar.ucar.edu
]

Michael Hudson

unread,
Feb 27, 1997, 3:00:00 AM2/27/97
to

As you can't understand much of what goes in comp.std.c++ without
understanding this, here goes:

Dr. Richard Botting wrote:
>
> I could do with a simple briefing describing the differences between
> a cast

A (C-style) cast maps to one of the new-style casts. Which one (or more
than one), however, depends.

I think it tries to become a static_cast, and if that fails it becomes a
reinterpret_cast, either of which may be combined with a const_cast.

> a constant cast

A const_cast changes the const/volatile qualification of its parameter,
and nothing else.

> a static cast

A static_cast basically performs any type conversions that would be
possible any way.
This is handy because
a) sometimes you want to disambiguate a function call
and
b) it can perform them backwards.

> a dynamic cast

A dynamic_cast casts around a class heirachy safely.

> a reinterpret cast

A reinterpret_cast is used to perform anything that can't be done any
other way. Use of reinterpret_cast's requires watching. It has been said
that any use of reinterpret_cast in a program is a sign of fundamental
flaws in the program, but I think this is a little strong.

>
> --
> dick botting

--
Regards,
Michael Hudson

Please don't email this address - it's not mine.

Stan Friesen

unread,
Feb 28, 1997, 3:00:00 AM2/28/97
to

In article <5evq3p$c...@news.csus.edu>, di...@silicon.csci.csusb.edu (Dr.

Richard Botting) writes:
|> I could do with a simple briefing describing the differences between
|> a cast

Any cast: any specific instance of a regular cast is equivalent to
one of the following types of cast except a dynamic_cast, possibly
followed by a const_cast.

|> a constant cast

A cast that adds or removes the specifier 'const' from a type, but makes
no other changes.

|> a static cast

A "safe" cast. Performs casts that would be legal as initializations
of variables, along with the inverses of any standard (implicit)
conversion. Uses only compile-time information to do the conversion.

[This means that static_cast<Derived *>(base_ptr) is legal, but dereferencing
it may cause undefined behavior, if the real dynamic type of the object
pointed to is not 'Derived'.]

|> a dynamic cast

Uses run time type information to perform a cast of pointers or references
to class type.
In particular, casts to derived classes, or casts sideways in a class lattice
are allowed, but they only succceed if the real type of the object pointed or
referred to actually *is* of the target type.

A dynamic cast of a pointer type returns NULL if it fails.

A dynamic cast of a reference type throws bad_cast if it fails.

The result is that ypu can safely actually *use* the results of a successful
dynamic cast.

|> a reinterpret cast

Any other legal cast.
The results are, except for casts to void*, implementation defined,
and are rarely portable or even safe.

--
s...@elsegundoca.ncr.com sar...@ix.netcom.com

The peace of God be with you.
---

Valentin Bonnard

unread,
Feb 28, 1997, 3:00:00 AM2/28/97
to

Dr. Richard Botting wrote:
>
> I'm feeling like I'm lost in twisty maze of little passages
> that all look alike.... Or was it a maze of little twisty passages
> that all look alike?
>
> In the December Draft/HTML Version I find:
>
> 5.2.7 Dynamic cast [expr.dynamic.cast]
> 1 The result of the expression dynamic_cast<T>(v) is the result of con-
> verting the expression v to type T. T shall be a pointer or reference
> to a complete class type, or "pointer to cv void". Types shall not be
> defined in a dynamic_cast. The dynamic_cast operator shall not cast
> away constness (_expr.const.cast_).
>
> 5.2.9 Static cast [expr.static.cast]

[The same as dynamic-cast; skipped]

>
> 5.4 Explicit type conversion (cast notation) [expr.cast]

[Nearly the same; skipped]

>
> I looked in my C++.FAQ but they didn't help too much.
>

> I could do with a simple briefing describing the differences between
> a cast

> a constant cast
> a static cast
> a dynamic cast
> a reinterpret cast

You should have read the others paragraphs of the specific
clauses ! The fisrt one is pretty boring and doesn't tell
much.

Summary of new-style casts
--------------------------

- static_cast: tell the compiler that you lost static type
information and want to recover it; the compiler should
trust you, but (as usual in C++), if you lie, you get
undefined behaviour; can only be used to recover info
on the un-qualified type, not to recover cv-qualifier
info.
-> See const-cast for that
-> See dynamic-cast when you don't want to tell the
compiler to trust you

static_cast is also appropriate for conversion betwen
numeric types

Example:

Base b;
Der d;
Base *b1 = &d, // you loose type info in the standard conversion
*b2 = &b;
Der* dp = static_cast<Der*> (b1); // OK
dp = static_cast<Der*> (b2); // Please don't lie like that;
// undefined behaviour

The standard: clear, except about void* -> T* conversions which
have IMO been forgoten.

- const_cast: nearly the same with cv-qualification, with
a difference: you can lie if you want

int i;
const int ci = foo;
const int *pic1 = &i, // you loose type info in the standard conversion
*pic2 = &ci;
int* pi = const_cast<int*> (pic1); // OK
pi = const_cast<int*> (pic2); // not true, but OK
*pi = 2; // don't write on a const ! undefined behaviour

IMO this is needed to use a const-unsafe library.

In these two cases you must ensure by other means that
the dynamic type (resp. dynamic constness) is what you
say it is (if you want to write to the variable in the
case of the const_cast).

This is the same as an union with a discriminant field:

struct I_know_what_I_contain {
enum { nothing, an_int, a_float } what;
union {
float f;
int i;
};
};

It's up to you to access the right field using 'what'.

- dynamic_cast<T*>: you ask if the object has a dynamic
type convertible to T; the compiler do the conversion if
so or return 0. Abuses of dynamic_cast lead to very bad
style and inneficient programs.

- reinterpret_cast: used to convert from unrelated pointer
types and to put a pointer in an integer and back;
implemantation defined execpt that reinterpret-casts
are value preserving when you go back to the original
type (if the intermediate type is large enough).

The standard: IMO reinterpret_casts is 10% handled by
the DWP, and by 90% by quality of implementation; while
it is clear that reinterpret_cast is intended to be used
for undefined/unspecified tricks, it should IMO be
converded better by the DWP.

In particular reinterpret_cast<[const] char*> should have
some meaning (other than implementation defined).

Also all the 'layout-compatible' stuff is pointless
if you can't portably cast betwen incompatibles types.

struct {
int i; // first member
} s;
*(reinterpret_cast<int*> (&s)) = 0;

struct {
float f;
int i; // any member
} s;
*(reinterpret_cast<int*> (&s)) = 0;

I'm not sure if the above stuff was guarantied to work
(with old style cast, ARM or ANSI C), but if it was,
it's no more guarantied since reinterpret_cast return
an unspecified value.

Old style casts
---------------

Old style casts are:
- if they convert betwen numeric types -> static_cast
- if they navigate a class hierarchy (to Base or to Der)
-> static_cast
- if they convert betwen unrelated types
-> reinterpret_cast

Also if cv-qualification is removed, a const_cast is added.

--

Valentin Bonnard
mailto:bonn...@pratique.fr
http://www.pratique.fr/~bonnardv (Informations sur le C++ en Francais)

0 new messages