C + + implicit type conversion

Posted by nrerup on Mon, 27 Dec 2021 18:17:22 +0100

Implicit type conversion has different conversion methods for different types. Generally, it can be divided into two types, arithmetic type and class type.

1. Arithmetic type conversion

The design principle of arithmetic type conversion is to avoid loss of precision as much as possible.

Specifically, there are the following reference rules:

  • Integer promotion: converts a small integer type to a larger integer type. For example, if the type of an operand is long double, another operand, whatever its type, will be converted to long double.
  • Converts a signed type to an unsigned type. Type conversion generally does not change the value of object memory. When an object of signed type is converted to unsigned type, its represented value may change, for example, int a = -1 (0xff); unsigned int b = a; The value of B is 255.
  • In conditional judgment, non Boolean types are automatically converted to Boolean types. If the value of pointer or arithmetic type is 0, it is converted to false; otherwise, it is converted to true.

Here is an example:

#include<iostream>
using namespace std;
int main()
{
    int a[]={1,2,2,3,4};
    int n=sizeof(a);
    if(-1>(n/sizeof(int)))
        cout<<"-1 is bigger than 5";
    else
        cout<<"-1 is less than 5";
    return 0;
}

Compile output:
analysis:
The reason is that the return type of sizeof() is unsigned int and - 1 is int, so - 1 is implicitly converted to unsigned int and oxffffffff, which is larger than 5 of course.

2. Class type conversion and explicit

C++ Primer mentions:
The constructor that can be called with a single parameter defines an implicit conversion from the parameter type to the class type
It should be noted here that "can be called with a single parameter" does not mean that the constructor can only have one parameter, but it can have multiple parameters, but those parameters have default arguments.

So, what is "implicit conversion"? The above sentence also says that it is an automatic conversion of a compiler from a constructor parameter type to this class type. Look at a code example:

class CxString  
{  
public:  
    char *_pstr;  
    int _size;  
    // Class declarations that do not use the explicit keyword are implicitly declared  
    CxString(int size)  
    {  
        _size = size;                // Default size of string  
        _pstr = malloc(size + 1);    // Allocate memory for string  
        memset(_pstr, 0, size + 1);  
    }  
    CxString(const char *p)  
    {  
        int size = strlen(p);  
        _pstr = malloc(size + 1);    // Allocate memory for string  
        strcpy(_pstr, p);            // Copy string  
        _size = strlen(_pstr);  
    }  
    // Destructors are not discussed here. Omit  
};  
  
    // Here is the call:  
  
    CxString string1(24);     // This is OK. Pre allocate 24 bytes of memory for CxString  
    CxString string2 = 10;    // This is OK. Pre allocate 10 bytes of memory for CxString  
    CxString string3;         // This is not possible because there is no default constructor and the error is: "CxString": no suitable default constructor is available  
    CxString string4("aaaa"); // This is OK  
    CxString string5 = "bbb"; // This is OK. CxString(const char *p) is called  
    CxString string6 = 'c';   // This is OK. In fact, CxString(int size) is called, and the size is equal to the ascii code of 'c'  
    string1 = 2;              // This is also OK. Pre allocate 2 bytes of memory for CxString  
    string2 = 3;              // This is also OK. Pre allocate 3 bytes of memory for CxString  
    string3 = string1;        // This is OK, at least the compilation is OK, but if the destructor is released with free_ pstr may report an error when the memory pointer is. The complete code must overload the operator "=" and handle memory release in it

In the above code, "CxString string2 = 10;" Why is this possible? In C + +, if the constructor has only one parameter, there will be a default conversion operation during compilation: convert the data of the data type corresponding to the constructor to this kind of object That is, "CxString string2 = 10;" In this code, the compiler automatically converts integers into CxString class objects, which is actually equivalent to the following operations:

CxString string2(10);  
or  
CxString temp(10);  
CxString string2 = temp;  

However, in the above code_ Size represents the size of string memory allocation, so the second sentence called "CxString string2 = 10;" And the sixth sentence "CxString string6 = 'c';" It is nondescript and easy to be confused Is there any way to stop this usage? The answer is to use the explicit keyword Let's modify the above code as follows:

class CxString 
{  
public:  
    char *_pstr;  
    int _size;  
     // Use the class declaration of the keyword explicit to display the transformation  
    explicit CxString(int size)  
    {  
        _size = size;  
        // The code is the same as above, omitting  
    }  
    CxString(const char *p)  
    {  
        // The code is the same as above, omitting  
    }  
};  
  
    // Here is the call:  
  
    CxString string1(24);     // This is OK  
    CxString string2 = 10;    // This is not possible because the explicit keyword cancels the implicit conversion  
    CxString string3;         // This is not possible because there is no default constructor  
    CxString string4("aaaa"); // This is OK  
    CxString string5 = "bbb"; // This is OK. CxString(const char *p) is called  
    CxString string6 = 'c';   // This does not work. In fact, CxString(int size) and ascii code with size equal to 'c' are called, but the explicit keyword cancels the implicit conversion  
    string1 = 2;              // This is also not possible because the implicit conversion is cancelled  
    string2 = 3;              // This is also not possible because the implicit conversion is cancelled  
    string3 = string1;        // This is also not possible, because the implicit conversion is cancelled, unless the class implements the overload of the operator "="

The explicit keyword prevents implicit automatic conversion of class constructors

As mentioned above, the explicit keyword is only valid for class constructors with one parameter. If the class constructor parameters are greater than or equal to two, there will be no implicit conversion, so the explicit keyword is invalid
However, there is an exception, that is, when all parameters except the first parameter have default values, the explicit keyword is still valid. At this time, when calling the constructor, only one parameter is passed in, which is equivalent to a class constructor with only one parameter. The example is as follows:

class CxString  // Using the keyword explicit declaration  
{  
public:  
    int _age;  
    int _size;  
    explicit CxString(int age, int size = 0)  
    {  
        _age = age;  
        _size = size;  
        // The code is the same as above, omitting  
    }  
    CxString(const char *p)  
    {  
        // The code is the same as above, omitting  
    }  
};  
  
    // Here is the call:  
  
    CxString string1(24);     // This is OK  
    CxString string2 = 10;    // This is not possible because the explicit keyword cancels the implicit conversion  
    CxString string3;         // This is not possible because there is no default constructor  
    string1 = 2;              // This is also not possible because the implicit conversion is cancelled  
    string2 = 3;              // This is also not possible because the implicit conversion is cancelled  
    string3 = string1;        // This is also not possible, because the implicit conversion is cancelled, unless the class implements the overload of the operator "="
    ```

Topics: C++ Back-end