473,395 Members | 1,343 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Type casting

This question has probably been asked a million time, but here it comes
again. I want to learn the difference between the three type cast operators:
static_cast, reinterpret_cast, dynamic_cast. A good way to do this is by
example. So I will give an example and please tell me what you think:

I have a base
class A
with a virtual destructor, and a
class B
that is it inherits publicly from A and defines som extra stuff.

If I have the following variables:

A* pA;
B* pB1 = new B();
B* pB2;

and the following assignment
pA = pB1;

which is most correct of the following
pB2 = static_cast< B* > (pA);
pB2 = reinterpret_cast< B* > (pA);
pB2 = dynamic_cast< B* > (pA);

The last one works only if I have RTTI set.
Why should I use one of them isntead of the other? Please could you explain
this to me as if I were a 6 year old? I have an idea about it, but I am
finding it difficult to understand that idea, if you know what I mean.

And thank you very much

Jacob
Jul 22 '05 #1
4 3422
* "Jacob Jensen" <ja***********************@yahoo.co.uk> schriebt:

I have a base
class A
with a virtual destructor, and a
class B
that is it inherits publicly from A and defines som extra stuff.

If I have the following variables:

A* pA;
B* pB1 = new B();
B* pB2;

and the following assignment
pA = pB1;

which is most correct of the following
pB2 = static_cast< B* > (pA); // 1
pB2 = reinterpret_cast< B* > (pA); // 2
pB2 = dynamic_cast< B* > (pA); // 3
reinterpret_cast is just a way of telling the compiler to regard the bits
as having some other type than the original, and that's dangerous. The bits
may not even be meaningful when regarded as a value of the new type. So you
have essentially no well-defined operations on the result, other than casting
it back to the original type.

In this context a reinterpret_cast is meaningless and incorrect and dangerous,
although it might seem to "work" with a given compiler.

static_cast says to the compiler: change the type appropriately if there is
a well-defined conversion to the new type -- just do it, I know it's safe.

In this situation static_cast is appropriate because _you_ know it's safe.

dynamic_cast is like a static_cast except you're saying: "I'm not quite sure
whether this is safe, could you please do a runtime type check at this point".

Since you do know that the cast is safe a dynamic_cast would be inappropriate,
but not right out incorrect, here.

Summing up, _in this situation_ the most appropriate choice from the three you
have listed is static_cast.

(Comment: a downcast can often be avoided by introducing a virtual method.)
The last one works only if I have RTTI set.


No, it works with any conforming C++ compiler.

However, some C++ compilers, e.g. Microsoft's Visual C++, can be configured to
act like non-C++ compilers.

And in fact, Microsoft's Visual C++ compiler does not act like a C++ compiler
by default; it must be configured to act like one (options /GX and /GR to support
exceptions and RTTI, plus possibly esoteric linker option to support standard
'main').

Jul 22 '05 #2
>
dynamic_cast is like a static_cast except you're saying: "I'm not quite sure whether this is safe, could you please do a runtime type check at this point".
Since you do know that the cast is safe a dynamic_cast would be inappropriate, but not right out incorrect, here.


Just a minor point to add, which the OP may not know.

The way that dynamic_cast says that a cast is unsafe is by returning 0 (or
NULL) in the case of pointers and by throwing an exception (std::bad_cast I
think) in the case of references.

john
Jul 22 '05 #3
> reinterpret_cast is just a way of telling the compiler to regard the bits
as having some other type than the original, and that's dangerous. The bits may not even be meaningful when regarded as a value of the new type. So you have essentially no well-defined operations on the result, other than casting it back to the original type.
Is it because a pointer to a type A may have a different byte representation
that a pointer to a type B?
But as you say, I will have "no well-defined operations on the result, other
than casting it back to the original type".
But is that not what I am doing? I am casting it back to the type it
originally was/is.
So if that is correct, then please tell me why I should not use it instead
of using static_cast (Note: Only tell me if my statement of casting it to
its original type is the correct)?
And when do I use reinterpret_cast then?

dynamic_cast is like a static_cast except you're saying: "I'm not quite sure whether this is safe, could you please do a runtime type check at this point".

Do I understand you correctly concerning the dynamic_cast thingy: There are
some cases when I do not know what type of pointer I have. And in that case,
I can try to cast it, and see if it gives a NULL pointer. That is my code
MUST handle the case where the cast is not valid. Am I right?
(Comment: a downcast can often be avoided by introducing a virtual method.)

I would be interested in seeing a simple example of this. I need the above
downcast, because I have some API functions which I have to use that only
take the base class pointer as argument. So I have to upcast my pointer to
call the function ( func1() ), and then downcast it in a function that is
called by func1(), which is a function I have defined.
The last one works only if I have RTTI set.


No, it works with any conforming C++ compiler.

However, some C++ compilers, e.g. Microsoft's Visual C++, can be

configured to act like non-C++ compilers.


Do you mean that all standard C++ compilers should have RTTI set?

Thank you again for your time. I really appreciate it.
Jul 22 '05 #4
* "Jacob Jensen" <ja***********************@yahoo.co.uk> schriebt:
* Alf wrote:

reinterpret_cast is just a way of telling the compiler to regard the bits
as having some other type than the original, and that's dangerous. The
bits may not even be meaningful when regarded as a value of the new type.
So you have essentially no well-defined operations on the result, other than
casting it back to the original type.
Is it because a pointer to a type A may have a different byte [you mean bit]
representation that a pointer to a type B?


It may in general, yes.

The standard lays out the rules in §5.2.10, with slightly different details
for different pointer types (pointer to function, to object, to member function),
but in general the only well-defined operation is to reinterpret_cast back to
the original type, in which case you get the original value back.

Exception: reinterpret_cast of null-pointer yields a valid null-pointer.

In your specific example I can't see any way the bits could be different,
but the standard is conservative: you can't use the result of a
reinterpret_cast for anything other than casting it back -- unless you
use knowledge of a particular compiler and system.

An example where it's obvious that different bit-level values must be
involved is when you have

class A{ ... };
class Middle1: public A { ... };
class Middle2: public A { ... };
class B: public Middle1, public Middle2 { ... };

Here a B object contains two different A subobjects. Casting using
static_cast from B* to Middle1* to A* gets you a pointer to one of them,
casting using static_cast from B* to Middle2* to A* gets you a pointer to
the other, and these two pointers can't very well be the same bit pattern,
for if they were then they would refer to the same A subobject.

In above paragraph I use 'casting' and 'static_cast' even though no actual
cast notation need be involved, since it's pure upcasting. But without
cast notation what you get _is_ a static_cast. It goes like:

#include <iostream>

struct A{ int ahum; };
struct Middle1: A { int m1; };
struct Middle2: A { int m2; };
struct B: Middle1, Middle2 { int bah; };

int main()
{
B object;
B* b = &object;
Middle1* m1 = b;
Middle2* m2 = b;
A* a1 = m1;
A* a2 = m2;

std::cout
<< a1 << "\n" // Some pointer value.
<< a2 << "\n" // Some different pointer value.
<< std::flush;

// Try to go directly from an A subobject to the B object.
// Not accepted, the compiler doesn't know _which_ A subobject.
// Not knowing where the pointer points it can't adjust it.
//
// B* bummer = static_cast<B*>( a1 ); // Nope.

// Go via the relevant subobject that _you_ know.
B* better = static_cast<B*>( static_cast<Middle2*>( a2 ) );

std::cout
<< b << "\n" // Some pointer value.
<< better << "\n" // The same pointer value.
<< std::flush;
}
But as you say, I will have "no well-defined operations on the result, other
than casting it back to the original type".
But is that not what I am doing? I am casting it back to the type it
originally was/is.
In your particular case: yes in practice no in standard. In general just no.

The reason is that the innocent upcasts are static_cast's, which in general
may change the pointer value (bitpattern).

A bitpattern-preserving (and not even that much is guaranteed!) reinterpret_cast
is then not guaranteed to get back the original value.
So if that is correct, then please tell me why I should not use it instead
of using static_cast (Note: Only tell me if my statement of casting it to
its original type is the correct)?
OK.

And when do I use reinterpret_cast then?


Only in very low-level, platform-specific code.

dynamic_cast is like a static_cast except you're saying: "I'm not quite
sure whether this is safe, could you please do a runtime type check at
this point".


Do I understand you correctly concerning the dynamic_cast thingy: There are
some cases when I do not know what type of pointer I have. And in that case,
I can try to cast it, and see if it gives a NULL pointer. That is my code
MUST handle the case where the cast is not valid. Am I right?


Yep. Except as John Harrison noted, if you're casting to reference instead
of to pointer what you get as ungood-signal is an exception, not NULL. With
casting to pointer you get NULL.

(Comment: a downcast can often be avoided by introducing a virtual

method.)

I would be interested in seeing a simple example of this. I need the above
downcast, because I have some API functions which I have to use that only
take the base class pointer as argument. So I have to upcast my pointer to
call the function ( func1() ), and then downcast it in a function that is
called by func1(), which is a function I have defined.


Off the cuff,

struct A{ virtual void something(){} };
struct B{ virtual void something(){ ... B stuff ... } };

void calledFunc( A* pObj ){ pObj->something(); } // Does B stuff.

void func1( A* pObj ){ calledFunc( pObj ); }

int main()
{
B obj;
func1( &obj );
}

(Actually the best explanation I know of for virtual functions is as a
solution to avoid downcasts in e.g. an arithmetic expression evaluator.
But that's a digression. It's a shame that example isn't wider known.)

If the above doesn't seem possible there are more advanced versions of the
same basic idea -- look up the "visitor pattern".

And if that doesn't seem possible perhaps some redesign can do the trick.

In general you should never need downcasts except when taking objects out
of polymorphic containers (that is, containers containing a bunch of
objects of different but related types).

The last one works only if I have RTTI set.


No, it works with any conforming C++ compiler.

However, some C++ compilers, e.g. Microsoft's Visual C++, can be
configured to act like non-C++ compilers.


Do you mean that all standard C++ compilers should have RTTI set?


Yes.

All C++ compilers must support RTTI and compile RTTI-based code
correctly, since RTTI is part of the language defined by the standard.

Without RTTI (or exceptions, or 'main' ;-) ) you have only a subset of C++.

--
A: Because it messes up the order in which people normally read text.
Q: Why is top-posting such a bad thing?
A: Top-posting.
Q: What is the most annoying thing on usenet and in e-mail?
Jul 22 '05 #5

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
by: maxim vexler | last post by:
in a book i am ready now : O'Reilly - Web Database Application with PHP and MySQL, 2nd ed. by David Lane, Hugh E. Williams on chapter 9 the author give an example for age validation :...
5
by: Suzanne Vogel | last post by:
** Isn't the 'static_cast' operator the same as traditional type casting? ie, Aren't the following ways of getting b1, b2 the same? // 'Derived' is derived from 'Base' Derived* d = new...
1
by: JohnK | last post by:
under the covers is type casting in VB.Net the same as C# ? myObject = CType(..,..) in VB.Net vs myObject = (SomeClass)aObject
1
by: chook | last post by:
Wherein differences between type casting in C++ : static_cast, dinamic_cast, reinterpret_cast, const_cast and C type casting, like xxx = (type)yyy; What, when and why is necessary to use?
9
by: Roman Mashak | last post by:
Hello, All! Given the sample piece of code I have: #include <stdio.h> #include <string.h> int main(void) { short int i, j;
7
by: Wayne M J | last post by:
I have worked out most type casting and the likes but I am curious about one aspect. Endpoint ep...; IPEndPoint iep...; .... ep = (EndPoint)iep; .... iep = (IPEndPoint)ep; ....
23
by: René Nordby | last post by:
Hi there, Is there anyone that knows how to do the following? I have a class A and a class B, that 100% inherits from class A (this means that I don't have other code in class B, than...
16
by: Enekajmer | last post by:
Hi, 1 int main() 2 { 3 float a = 17.5; 4 printf("%d\n", a); 5 printf("%d\n", *(int *)&a); 6 return 0; 7 }
7
by: Ben R. | last post by:
How does automatic type casting happen in vb.net? I notice that databinder.eval "uses reflectoin" to find out the type it's dealing with. Does vb.net do the same thing behind the scenes when an...
11
by: Frederic Rentsch | last post by:
Hi all, If I derive a class from another one because I need a few extra features, is there a way to promote the base class to the derived one without having to make copies of all attributes? ...
0
by: Charles Arthur | last post by:
How do i turn on java script on a villaon, callus and itel keypad mobile phone
0
by: ryjfgjl | last post by:
If we have dozens or hundreds of excel to import into the database, if we use the excel import function provided by database editors such as navicat, it will be extremely tedious and time-consuming...
0
by: ryjfgjl | last post by:
In our work, we often receive Excel tables with data in the same format. If we want to analyze these data, it can be difficult to analyze them because the data is spread across multiple Excel files...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
by: Hystou | last post by:
Overview: Windows 11 and 10 have less user interface control over operating system update behaviour than previous versions of Windows. In Windows 11 and 10, there is no way to turn off the Windows...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.