简体   繁体   中英

Is it possible to completely avoid C-style casts in C++?

I do not believe that it is possible to completely avoid C-style casts when writing C++. I was surprised to find out that I needed to use a C-style cast to avoid a compiler truncation warning:

short value_a = 0xF00D;                     // Truncation warning in VS2008
short value_b = static_cast<short>(0xF00D); // Truncation warning in VS2008
short value_c = (short)0xF00D;              // No warning!

Are there other scenarios where there is no C++-style substitute for a C-style cast?

In C++, the C-style cast is defined (§5.4) in terms of C++-style casts. So for every cast you can do C-style, there's a matching C++-style cast (almost).

The "almost" is that C-style casts ignore base class accessibility. That is, there is no equivalent C++-style cast for the following:

struct foo {};
struct bar : private foo {};

bar b;
foo* f = (foo*)&b; // only way this can be done in a well-defined manner

So, no it's not strictly-speaking possible to completely ditch C-style casts. But the number of areas where a (combination of) C++-style casts doesn't suffice is few in count.


The above is the "language answer". What you're experiencing has nothing to do with C-style casts versus C++ casts, but just compiler implementation. Warnings are absolutely implementation-specific, and have nothing to do with C++.

So don't make the mistake of using your findings on this particular compiler in this particular situation for concluding things about C++ in general .

You are just trying to obfuscate your code, it is as simple as that. And the compiler is completely correct in telling you so.

If you have a precise idea what the assigned value should be, use that. My guess is that you have some unfounded presumption of short being 16 bit wide and that the sign representation of the target machine is two's complement. If that is so, assign -4083 to your variable. If you just need your variable as a bit vector, use an unsigned type.

As far as C is concerned the standard simply says about conversion from one integer type to another:

Otherwise, the new type is signed and the value cannot be represented in it; either the result is implementation-defined or an implementation-defined signal is raised.

I imagine the the point of view of C++ with this respect is not much different. Other answers mention border cases where in C++ you would need a `C'-style cast to overrule all typechecks that C++ gives you. Feeling the need for them is an indication of bad design.

The case that you give as an example is certainly not one for which I would find any valid circumstances.

Yes, it is completely possible.

I never use C-style casts. I can write hundreds of thousands of lines of code without having to revert to using reinterpret_cast , C++'s closes cousin to the C-style cast. The only times I have to use reinterpret_cast is when doing socket programming -- a fairly narrow domain, in the big picture.

You don't need to use C-style casts, either. In your other post , you said

I could just use a negative value,

short my_value = -4083;

but in my code it is much more understandable to use hexadecimal.

So in this case you didn't have to use the cast. You chose to.

I was surprised to find out that I needed to use a C-style cast to avoid a compiler truncation warning

I see it the other way around: You use a C-style cast to prevent the compiler from warning you , and I see this as a severe disadvantage of the C-style cast.

if you feel you know what you're doing, then shut up the compiler for this one case by using a compiler-specific way. For example, for VC use something like

#pragma warning(push, disable: XXXX)
// code goes here
#pragma warning(pop)

There are 4 c++ style casts, const_cast, reinterpret_cast, static_cast and dynamic_cast. They work as follows:

// const_cast casts away constness or adds it
const int const_integer = 5;
const_cast<int>(const_integer) = 3;

// static_cast will perform standards defined casts and will 
// cast up or down a c++ inheritance hierarchy without checking the result of the cast
struct b {};
struct a : public b {};
struct c {};
double value = static_cast<double>(0.0f);
b* b_value = new b;
a* a_value = static_cast<a*>(b_value);

// dynamic_cast will perform any cast that static_cast will, but will check to see
// if the cast makes sense. If the values are not pointers, this cast can throw
b* value_b = new b;
a* value_a = new a;
b* new_b = dynamic_cast<b*>(value_a); // will return NULL
a* new_a = dynamic_cast<a*>(value_b); // will not return NULL    

// reinterpret_cast will change any type to any other type, as long as the constness of the types is the same.
// the behavior of this cast is implementation specific.
double* a = new double;
*a = 0.0f;
int *b = reinterpret_cast<int*>(a);

A c-style cast in c++ simply tries to perform those casts in a specific order until one of them works. That order is as follows:

  • a const_cast
  • a static_cast
  • a static_cast followed by a const_cast
  • a reinterpret_cast, or
  • a reinterpret_cast followed by a const_cast.

So, in short, you can do any c-style cast in c++, because a c-style cast in c++ is just some arrangement of c++ style casts. Get it?

In these cases, you can use reinterpret_cast . It was meant for a replacement of a unchecked C-style cast. The typical note here: this is unchecked cast, and should be avoided when possible by using the other available: const_cast , dynamic_cast , etc.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM