Type conversion
In C++, certain types are related. If two types are associated, then when the program needs one of the types of operation objects, the object or value of the other associated type can be replaced.
In other words, if the two types can be converted to each other, they are related.
For example, consider the following expression, which aims to initialize ival to 6:
int ival = 3.541 + 3;//The compiler may warn that the operation has lost accuracy
The two operation objects of addition have different types: the type of 3.541 is double, and the type of 3 is int. C++ language will not directly add two different types of values, but will first try to unify the types of the operation object according to the type conversion rules before evaluating the value. The above type conversion is automatically executed without programmer intervention, and sometimes it does not even require programmer understanding. Therefore, they are called implicit conversions.
Implicit conversions between arithmetic types are designed to avoid loss of accuracy as much as possible. Many times, if there are both integer type operation objects and floating point type operation objects in the expression, the integer type will be converted to floating point type. In the above example, 3 is converted to double type, and then floating point addition is performed, and the type of the result is double.
The initialization task is to be completed next. During the initialization process, because the type of the initialized object cannot be changed, the initial value is converted to the type of the object. This example is still used to illustrate that the result of the double type obtained by the addition operation is converted into a value of the int type, which is used to initialize the ival. The decimal part is ignored when converting from double to int. In the above expression, the value 6 is assigned to ival.
When does an implicit type conversion occur
In the following cases, the compiler will automatically convert the type of the operation object:
In most expressions, integer values smaller than int type are first promoted to larger integer types. In the condition, non-boolean values are converted to boolean types. During the initialization process, the initial value is converted into the type of the variable: In the assignment statement, the right-side operation object is converted into the type of the left-side operation object. If there are multiple types of operation objects for arithmetic or relational operations, they need to be converted to the same type. Type conversion also occurs when function calls.
Arithmetic transformation
Arithmetic conversion means converting one arithmetic type into another arithmetic type. The rules of arithmetic conversion define a set of hierarchies of type conversions, where the operator's operation object will be converted to the widest type. For example, if the type of an operation object is long double, then no matter what the type of another operation object is, it will be converted to a long double. There is also a more common situation where when there are both floating point types and integer types in the expression, the integer value will be converted to the corresponding floating point type.
Integer lift
Integral promotion is responsible for converting small integer types into larger integer types. For types such as bool, char, signed char, unsigned char, short and unsigned short, as long as all their possible values can exist in int, they will be promoted to int type, otherwise, promoted to unsigned int type. As we are familiar with, the boolean value false is increased to 0 and true is increased to 1.
Larger char types (wchar_t, char16_t, vchar32_t) are promoted to the smallest type among int, unsigned int, long, unsigned long, long and unsigned long long, provided that the converted type must accommodate all possible values of the original type.
Unsigned type operation object
If the types of operation objects of tree operators are inconsistent, these operation objects will be converted to the same type. However, if the type of the tree operation object is an unsigned type, the conversion result depends on the relative size of each integer type in the machine.
As usual, perform the integer promotion first. If the type of the result matches, no further conversion is required. If the types of two (upgraded operation objects are either signed or unsigned, the smaller type of operation objects are converted to larger types.
If one operation object is an unsigned type and the other operation object is a signed type, and the unsigned type in it is not less than the signed type, then the signed operation object is converted to an unsigned. For example, suppose that the two types are unsigned int and int, the operation object of type int is converted to unsigned int type. It should be noted that if the value of type int happens to be negative.
The remaining case is that the signed type is larger than the unsigned type, and the result of the conversion depends on the machine. If all values of the unsigned type can exist in the signed type, the unsigned type operation object is converted to the signed type. If not, then the signed type operation object is converted to an unsigned type. For example, if the types of two operation objects are long and unsigned int, and the sizes of int and long are the same, the operation object of long type is converted to unsigned int type; if the long type takes up more space than int, the operation object of unsigned int type is converted to long type.
Understand arithmetic transformations
One way to understand arithmetic transformation is to study a large number of examples:
bool flag;char val; short sval; unsigned short usval; int ival; unsigned int uival; long lval;unsigned long ulval; float fval; double dval; 3.14159L+ 'a'; // "a" is promoted to int, and then the int value is converted to long doubledval+ival;//Convert ival to doubledval+fval;//Convert fval to doubleival=dval;//Dval is turned into (after removing the decimal part) intflag=dval;//If dval is 0, then flag is false, otherwise f1ag is Lruecval+fval;//Cval is promoted to int, and then the int value is converted to floatsval+cval;//Sval and cval are both promoted to intcval+lval;//Cval transfer to longival+ulval;//Ival converts to unsigned longusval+ival;//Elevate according to the size of space occupied by unsigned short and intuival+lval;//according tohnsigned intandlongThe size of the space occupied is converted
In the first addition operation, the lowercase letter 'a' is a char-type character constant, which can actually represent a numeric value. What is this numeric value completely depends on the character set on the machine. In our environment, the numeric value corresponding to ‘a’ is 97. When adding 'a' to a number of long double type, the value of char type is first promoted to int type, and then the value of int type is converted to long double type. Finally we add this converted value to that literal value. The last two expressions with unsigned type values are also interesting, and their results are machine-dependent.
Other implicit type conversion
In addition to arithmetic conversion, there are several implicit type conversions, including the following.
Convert arrays to pointers: In most expressions that use arrays, the array is automatically converted into a pointer to the first element of the array:
int ia[10];//Array with 10 integersint*ip = a;//iaConvert to a pointer to the first element of the array
When an array is used as a parameter to the decltype keyword, or as an operation object for operators such as address character (&), sizeof, and typeid, the above conversion will not occur. Similarly, if an array is initialized with a reference, the above conversion will not happen. Pointer conversion: C++ also specifies several other pointer conversion methods, including constant integer value 0 or literal value nullptr that can be converted to any pointer type; pointers to any non-quantity can be converted to void*; pointers to any object can be converted to const void*.
There is another way to convert pointer in the shape room.
Convert to boolean type:There is a mechanism for automatic conversion from an arithmetic type or pointer type to a boolean type. If the value of the pointer or arithmetic type is 0, the conversion result is false; otherwise the conversion result is true:
char*cp=get_string(); if(cp) /*...*/ //If pointer cp is not 0, the condition is truewhile(*cp)/*...*///if*cpNot an empty character,The condition is true
Convert to constants: Allows to convert pointers to non-constant types to pointers to corresponding constant types, and the same is true for references. That is, if 0 is a type, we can convert a pointer or reference to 0 into a pointer or reference to a const:
int i; const int &j =i; //References of non-const to const intconst int*p=&i; //Convert non-const addresses into const addressesint &r = j,*q= p; //mistake:Not allowedconstConvert to a non-volume
The opposite transformation does not exist because it tries to remove the underlying const. Conversion of class type definition: Class type can define conversions automatically performed by the compiler, but the compiler can only perform one conversion of class type at a time. We will see an example where if multiple conversion requests are made at the same time, these requests will be denied.
Our previous program has used class type conversion: one is to use C-style strings where standard library strings are required; the other is to read in the conditional part:
string s, t= "a value";//Convert string literal value to string typewhile(cin >> s) // while The conditions part ofcin Convert to boolean
Condition ( cin >> s ) reads the content of cin and uses cin as its evaluation result. The conditional part originally required a Boolean value, but what is actually checked here is the value of the istream type. Fortunately, the IO library defines the rule for converting from istream to boolean value. According to this rule, cin is automatically converted to boolean value. What exactly is the Boolean value obtained is determined by the state of the input stream. If the last read is successful, the Boolean value obtained by the conversion is true: On the contrary, if the last read is unsuccessful, the Boolean value obtained by the conversion is false.
Explicit conversion
Sometimes we want to explicitly cast an object to another type. For example, if you want to perform floating point division in the following code:
int i,j; double slope=i;
It is necessary to use some method to explicitly convert i and/or j into double, which is called cast.
WARNING: Although casting is sometimes necessary, this approach is inherently very dangerous.
Named cast
A named cast has the following form:
cast-name<type>(expression)
where type is the target type of conversion and expression is the value to be converted. If type is a reference type, the result is an lvalue. cast-name is one of static_cast, dynamic_cast, const_cast and reinterpret_cast. dynamic_cast supports runtime type recognition.
static_cast
Any type conversion with a well-defined type, as long as it does not contain the underlying const, can be used. For example, by casting an operation object to a double type, you can make an expression perform floating point division:
//Can perform casting to perform floating point divisiondouble slope=static_cast<double>(j)/i;
static_cast is very useful when you need to assign a larger arithmetic type to a smaller type. At this point, casting tells the program's readers and compilers: we know and don't care about potential precision losses. Generally speaking, if the compiler finds that a larger arithmetic type tries to assign a value to a smaller type, a warning message will be given; but when we perform an explicit type conversion, the warning message will be closed.
static_cast is also very useful for type conversions that cannot be performed automatically by the editor. For example, we can use static_cast to retrieve the value that exists in the void* pointer:
void+p=&d;//Correct: The address of any non-const object can be stored in void* //Correct: Transfer void* back to the initial pointer typedouble*dp=static_cast<double*>(p);
When we store the pointer in void* and cast it back to the original type using static_cast, we should make sure that the value of the pointer remains unchanged. That is to say, the result of the cast will be equal to the original address value, so we must ensure that the type obtained after the conversion is the type pointed to by the pointer. Once the types do not match, undefined consequences will occur.
const_cast
const_cast can only change the underlying const of the operation object:
const char*pc; char*p=const_cast<char*>(pc);//correct:But bypWriting values is undefined behavior
For the behavior of converting a constant object into a non-const object, we generally call it "cast away the const property". Once we remove the const property of a tree object, the compiler no longer prevents us from writing to the object. If the object itself is not a constant, it is legal to use casting to obtain write permissions. However, if the object is a constant, using const_cast to perform the write operation will have undefined consequences.
Only const_cast can change the constant properties of an expression. Using other forms of naming casting to change the constant properties of an expression will raise a compiler error. Similarly, you cannot use const_cast to change the type of an expression:
const char*cp; //Error: static_cast cannot convert according to const propertieschar*q = static_cast<char*>(cp); static_cast<string>(cp);//Correct: Convert string literals to string typeconst_cast<string>(cp);//Error: const_cast only changes the constant attribute
const_cast is often used in contexts with function overloading
reinterpret_cast
reinterpret_cast usually provides a lower-level reinterpretation of the bit pattern of the operation object. For example, suppose there is the following conversion
int *ip; char*pc=reinterpret_cast<char*>(ip);
We must remember that the real object referred to by pc is an int rather than a character. If pc is used as an ordinary character pointer, an error may occur at runtime. For example:
string str(pc);
Can cause exception runtime behavior.
Using reinterpret_cast is very dangerous, and the example of initializing str with pc proves this well. The key problem is that the type has changed, but the compiler does not give any warning or error prompts. When we initialize PC with an int address, since we explicitly claim that this conversion is legal, the compiler will not issue any warning or error messages. Next, when using PC, it will determine that its value is of type char*, and the compiler cannot know that it actually stores a pointer to int. The end result is that in the above example, although initializing str with PC is of no practical significance and may even cause worse consequences, this operation is syntactic only. It is very difficult to find the causes of this type of problem. This is especially true if the statements that cast ip to pc and the statements that initialize string objects with pc are divided into different files.
WRNING: reinterpret_cast is essentially a machine-dependent. To use reinterpret_cast safely, you must have a good understanding of the types involved and the process of compiling the conversion.
Suggestions: Avoid casting
Casting interferes with normal type checking, so we strongly recommend that programmers avoid casting. This suggestion is especially true for reinterpret_cast, as such type conversions are always full of risks. It is understandable to use const_cast in the context of overloaded functions, and this will be found in; but in other cases, using const_cast means that the program has some design flaw. Other casts, such as static_cast and dynamic_cast, should not be used in frequency. Every time a coercive type conversion statement is written, you should repeatedly consider whether the same goal can be achieved in other ways. Even if it is really unavoidable, you should try to limit the scope of type conversion values and record all assumptions about the related types, which can reduce the chance of errors. ′
Old-style cast
In earlier versions of C++, explicit casting included two forms:
type(expr);//Crew type conversion in function form(type)expr;//CLanguage style cast
Depending on the type involved, old-style casting has similar behaviors to const_cast, static_cast or reinterpret_cast, respectively. When we perform old-style casting somewhere, if it is also legal to convert to const_cast and static_cast, its behavior is consistent with the corresponding naming conversion. If the replacement is not legal, the old cast performs a function similar to reinterpret_cast:
char *pc=(char*)ip;//ipis a pointer to an integer
The effect is the same as using retnterpret_cast.
Summarize
The above is personal experience. I hope you can give you a reference and I hope you can support me more.