C ++ Introduces New Explicit conversions such as const_cast and reinterpret_cast, even some experienced C ++ programmers make mistakes in some details. It is true that since we can simply write:
Int I = (INT) P; // P is a pointer
Why should we use this explicit conversion?
Int I = reinterpret_cast <int> (P );
What about such a complicated form?
The purpose of this article is to briefly introduce the C ++ type conversion system and discuss the usage and extension.
1. Why type conversion?
Type conversion is used to convert a type value to another type. Programming languages like C ++ are strongly typed, so each value has its corresponding type. To convert a value to another type, you need to use one of the following methods: implicit conversion, explicit conversion, and non-conversion. Suppose we use the old explicit conversion:
Char c = 'a ';
Int * P = NULL;
Int A = C; // implicit conversion
A = (INT) P; // explicit conversion
Double D = (double) P; // cannot be converted
Generally, implicit conversions mean that the compiler deems your conversions reasonable or safe. Explicit conversions mean that the compiler can find a conversion method, but they do not guarantee the security of the conversion, therefore, the programmer needs to point out that the conversion fails, which means that the compiler cannot find a direct path for type conversion.
2. Why is explicit C ++ style conversion required?
The explicit conversion of the C ++ style provides us with more precise semantics and the possibility of further extension. In C, we can use a simple (int *) to complete the following conversion:
Const char * s = 0;
Int * P = (int *) S;
This statement not only converts the type, but also removes the const. Generally, if we see a free explicit conversion, we cannot immediately know the author's intention, which also paves the way for future errors. The real conversion of the C ++ style adds security by distinguishing various conversion situations: const_cast is used to cancel const, volatile, and other modifications, and static_cast is used to convert related types, use reinterpret_cast to perform low-level conversions ,.... An example shows how accurate these conversions are:
Class Interface
{
Int member;
};
Class base {};
Class derived: public interface, public base {};
Int main ()
{
Base * B = 0;
Derived * D1 = reinterpret_cast <derived *> (B );
Derived * D2 = static_cast <derived *> (B );
}
In this Code, both cast statements are valid but have different meanings. The former means that "the value of B pointer is directly assigned to D1 and interpreted as the derived type", and the latter means "Convert based on the relevant type information. If possible, offset the pointer B ". In the above example, D1 and D2 are not equal! Probably because many books have said: If you want to convert pointers to each other, you should use reinterpret_cast. Therefore, many programmers use reinterpret_cast to convert all pointer types, although they usually do not get errors, but it is not a small risk.
3. Examples
(1) itf_cast
In COM, if I have an interface pointer pointing to ihtmldocument and want to obtain an ipersistfile pointer, we can use the following code:
Ipersistfile * ppersistfile;
If (failed (phtmldocument-> QueryInterface (iid_ipersistfile, (lpvoid *) & ppersistfile )))
Throw something;
This code is simple but not straightforward enough, so we can implement this function:
Template <typename T1, typename T2>
T1 itf_cast (t2 V2)
{
If (V2 = 0)
Return 0;
T1 V1;
If (failed (v2-> QueryInterface (_ uuidof (* V1), (lpvoid *) & V1 )))
Throw bad_cast ();
Return V1;
}
Then we can write the preceding statement
Ppersistfile = itf_cast (phtmldocument );
This is very intuitive. Readers may find that _ uuidof is not defined by standard C ++, but an extension of VC. In fact, you can use traits to easily implement the same function.
(2) stream_cast
Sometimes, we often encounter conversion problems between custom types, such as STD: string and double, or even conversions such as STD: string and rect. If both types involved in conversion define input and output operations (precisely, the source type supports output operations, and the target type supports input operations ), we can use the following method for conversion:
Template <typename T1, typename T2>
T1 stream_cast (const T2 & V2)
{
STD: stringstream STR;
STR <V2;
T1 T1;
STR> T1;
If (! Str)
Throw bad_cast ();
Return T1;
}
In this way, you can use the following statement for conversion:
String S ("0.5 ");
Double D = stream_cast <double> (s );
(3) safe_cast
Sometimes we want our Explicit conversions to be secure. Here, the secure definition is that this value is lossless for both types of Sino-German representation. That is, (T2) (T1) V1 = V1. Then we can define an explicit conversion like this:
Template <typename T1, typename T2>
T1 stream_cast (const T2 & V2)
{
If (T2) (T1) V2! = V2)
Throw bad_cast ();
Return (T1) V2;
}
Therefore, stream_cast <char> (1000); such a statement throws an exception.
The above is my personal understanding and opinions on the explicit type conversion of the C ++ style. I hope you will discuss it with others.