C++ class implicit conversion and cast overload details

  • 2020-04-02 01:30:39
  • OfStack

Before writing this article, let's review the matching sequence that the compiler USES to determine which function to call:
(1) find and use the function that most conforms to the function name and parameter type (including the return value), and call if found;

(2) otherwise, find a function template and instantiate it to produce a matching overloaded function, if found, call it;

(3) otherwise, look for an overloaded function that can be type-cast for parameter matching, and if found, call it.

If none of the above steps finds a matching function, the call is wrong. If the call has more than one match selector, the call match is ambiguous and is an error.
 
Type conversion is the mapping of a value of one type to a value of another. Type conversions actually contain two types: automatic implicit and forced.

The automatic implicit conversion rules for internal data types provided by the C language compilation system are as follows:

1. When a program performs arithmetic operations, a low type can be converted to a high type.

2. In an assignment expression, the value of the expression on the right is automatically implicitly converted to the type of the variable on the left and assigned to it.

3. When a function is called, the argument value is assigned to the parameter, and the system implicitly converts the argument to the parameter's type and assigns it to the parameter.

4. When a function has a return value, the system will automatically convert the return expression type to the function type and assign the value to the calling function.

In the above cases, the system will perform implicit conversion. A compilation error occurs when two data types are found incompatible in a program and the implicit conversion cannot be automated. Such as:
Int * p = 100;
In this case, the compiler will report an error. To eliminate the error, you can do the following type casting:
Int * p = (int *)100;
Explicitly converts an integer number of 100 to a pointer type.

Constructors have type conversion capabilities

In practice, when a constructor for a single parameter is provided in a class definition, the class provides a way to convert values or variables of other data types to user-defined data types. Thus, you can say that the constructor for a single parameter provides the ability to transform the data. Here is an example to further illustrate the type conversion capability of a single-argument constructor.


#include
classA 
{
public:
A(){ m=0; } 
A(doublei) { m=i; } 
voidprint() { cout<<M< 
private:
doublem; 
};

voidmain() 
{
Aa(5); 
a=10; //A and 10 are different data types
a.print();
}

The output result of the program is:
10
In this program, the assignment statement a=10; The value 10 on both sides of the assignment number and object a are two incompatible data types, but the main reason it passes through the compiler and produces the correct results is because of the single-argument constructor. The compiler converts an integer value of 10 to A double using standard data type conversions, and then converts A double value to A type A using the single-argument constructor defined in the class, and finally assigns it to A. These conversions are done automatically and implicitly.

One more thing about the above program:
Aa = 10;
and
Aa;
A = 10;
The former initializes a, and the compiler tries to implicitly convert 10 to type a, which causes the a (doublei) constructor of a to be called directly.
The latter is an assignment statement, and the compiler creates A temporary object and implicitly converts 10 to type A. If we show the call
(A) 10;
This also creates A temporary object, causing the constructor of A to be called.

It is also important to note that the compiler only does one implicit conversion (except for the built-in types of the C time library such as intshort char, etc.), which are illustrated in the following statement:
M_rst - > The GetFields () > The GetItem (nCol) - > Value = (_bstr_t) sValue;
The above Value is a variant of COM, and "Value=" causes the operator= (_bstr_t) to be called. If you omit (_bstr_t) above, the compiler will have an error, because without an overload like operator= (char*), the compiler will not perform more than two implicit conversions for us.

During a function call, operator overloading and construction are also function calls, and an implicit conversion can occur if the matching function is not ambiguous. If the Value variant class of the previous sentence has only one copy = (_bstr_t), even write this - > Value = sValue; The compiler also attempts to implicitly convert sValue to type _bstr_t.

There's another case

classA 
{
inta; 
public:
A(){ }; 
A(int_a) { a = _a; }; 
Operatorint() { return a; } 
}

There is the following call:

Aa(10); 
Aa2 = (int)(int)a;   // Only the equivalent of Aa2 = (int)a;  Because the first one has already been converted int And the second // I don't have to turn it anymore 

Interesting, class A has both the construction of implicitly converting an int to A, and the int() conversion function for casting, (int) (int) A will be performed in the manner of proximity principle. If the nearby conversion fails, the compiler will report an error. Such as:

classB 
{
};
Aa2 = (B)a; 
 or 
Aa2 = (B)10; 

Error reported by compiler: "errorC2440: type cast ": unable to convert from" int "to" B ""
You can see how important our own constructs and transformations are.

The transition function
The cast function, also known as a type cast member function, is a non-static member function in a class. Its definition format is as follows:

   class< Type specifier 1>
    {
     public:
      operator< Type specifier 2>();
 ... 
    }

This transformation function defines the function by < Type specifier 1 > to < Type specifier 2 > Mapping between. As you can see, conversion functions are used to convert data of one type into another type. Here is an example of what the transformation function can do.

#include

classRational 
{
public:
Rational(intd, int n) 
{
den= d; 
num= n; 
}
operatordouble();//Type conversion function
private:
intden, num; 
};

Rational::operatordouble() 
{
returndouble(den)/double(num); 
}

voidmain() 
{
Rationalr(5, 8); 
doubled = 4.7; 
d+= r;  //This sentence will call the implicit conversion, equivalent to d= (double)r;
cout<<d<<ENDL;
}

Program output result:
5.325

The program knows that d is a double value and r is an object of the Rational class. The addition of these two different types of data is possible because of the conversion function operatordouble(). To enable the addition described above, the compilation system first checks the description of class Rational to see if the following conversion function can convert the operands of type Rational to the operands of type double. Since the transformation function operatordouble() is described in the Rational class, it can do this type conversion while the program is running, so d=r is implemented in the program; In the operation.

The following points should be noted when defining the transformation function:
(1) the transformation function is a user-defined member function, but it should be non-static.
(2) the conversion function cannot have a return value. (this means no return value in the declaration)
(3) the conversion function does not take any parameters.
(4) conversion function function can not be defined as friend function.

The name of the conversion function is the target type of the type conversion, so you no longer need to specify a return value type for it. Conversion functions are used to convert values or variables of this type to other types without taking arguments.

The constructor in the class does the conversion from other types to class types, and the overloading cast does the conversion from class types to other types.


Related articles: