Detailed explanation of c++---type conversion

Type conversion in c language

In C language, if the left and right sides of the assignment operator have different types, or the formal and parameter types do not match, or the return value type is inconsistent with the received return value type, type conversion needs to occur. There are a total of two forms in C language Type conversion: implicit type conversion and explicit type conversion. Implicit type conversion can be used when two data types are related. For example, implicit type conversion can be used between int char double long, such as the following code:

int main()
{
    
    
	int i = 10;
	double d = i;
	printf("%d  %.2f", i, d);
	return 0;
}

The results of the operation are as follows:
Insert image description here
However, if the correlation between the two data is not strong or completely unrelated, you cannot use implicit type conversion and must use forced type conversion. For example, the following code: double and int* are two unrelated things. type, an error will be reported when using implicit type conversion. For example, the following code:

int main()
{
    
    
	int i = 10;
	int* pi = &i;
	int d = pi;
	return 0;
}

Insert image description here

However, if you use forced type conversion, no error will be reported here. For example, the following code:

int main()
{
    
    
	int i = 10;
	int* pi = &i;
	int d = (int)pi;
	printf("%d  %p", d, pi);
	return 0;
}

Insert image description here
Although there are two conversion methods in C language, the visibility of conversion is relatively poor. All conversion forms are written in the same form, making it difficult to track wrong conversions. For example, some places will automatically perform integer promotion, and some will automatically perform integer promotion. Truncation will occur again, and these operations are secretly performed by itself, so sometimes it will cause some errors. In order to solve this problem, C++ provides 4 types of conversion to solve the problem caused by C, but Because C++ needs to be compatible with the C language, the conversion style of the C language can also be used in C++.

static_cast

static_cast uses similar types of conversions. For example, int and char belong to similar types, and int and double also belong to similar types. Then we can use static_cast to convert these types. The method of using angle brackets is also very simple. Write the type you want to convert, fill in the brackets with the object you want to convert, and finally assign it to the object of the corresponding type, for example, the following code:

int main()
{
    
    
  double d = 12.34;
  int a = static_cast<int>(d);
  cout<<a<<endl;
  return 0;
}

Here, the variable d is converted to the int type and assigned to the variable a of the int type.

reinterpret_cast

reinterpret_cast is used to convert between unrelated types. For example, int and int* are unrelated types, so the usage method here is the same as the static_cast above. For example, the following code:

int main()
{
    
    
 double d = 12.34;
 int a = static_cast<int>(d);
 cout << a << endl;
 // 这里使用static_cast会报错,应该使用reinterpret_cast
 //int *p = static_cast<int*>(a);
 int *p = reinterpret_cast<int*>(a);
 return 0;
}

const_cast

This conversion is to remove the original const attribute, that is, the const variable can be changed into a non-const variable, such as the following code:

int main()
{
    
    
	const int i = 10;
	int* p = const_cast<int*>(&i);
	*p = 20;
	cout << i << endl;
	cout << *p << endl;
	return 0;
}

The type obtained by &i was originally const int *, but after being modified by const_cast, it became int *, so it can be assigned normally. However, if you run the above code, you will find this result: So why is this
Insert image description here
? The pointer p points to the variable i, but why are the results printed here different? Let's check it through debugging.
Insert image description here
We can see that the content seen by debugging and the printed content are actually different. So why is this? The reason is very simple because by default the compiler thinks that the variable modified by the const variable will not be modified, so it will be placed in the register. In this way, when using this variable, it will directly get the variable from the register, and then modify the variable i. The content in the memory will be modified, but the monitoring window accesses the data from the memory instead of the register, so it looks different. To solve this problem, you have to add a volatile keyword in front of the variable like this It will not be fetched from the register, but from the memory. Then the code here is as follows:

int main()
{
    
    
	volatile const int i = 10;
	int* p = const_cast<int*>(&i);
	*p = 20;
	cout << i << endl;
	cout << *p << endl;
	return 0;
}

The results of the operation are as follows:
Insert image description here
const_cast removes the const attribute and divides it into a separate type. This is to warn you that you should be careful when using this very dangerous method.

dynamic_cast

Dynamic_cast is used to convert a pointer/reference of a parent class object into a pointer or reference of a subclass object (dynamic conversion) Upcast
: subclass object pointer/reference -> parent class pointer/reference (no conversion required, assignment compatibility rules)
Downward transformation: parent class object pointer/reference -> subclass pointer/reference (dynamic_cast transformation is safe).
So why is it said that dynamic_cast transformation is safe here? The reason is very simple because subclasses can be converted into parent classes, and parent classes can also be converted into subclasses. However, problems may arise here. After the parent class becomes a subclass, the pointed space may be illegally accessed, so there is Dynamic_cast will check the conversion. If the parent class is converted to a subclass, it will prevent the conversion from failing. For example, the following code:

class A
{
    
    
public:
	virtual void f() {
    
    }

	int _a = 0;
};

class B : public A
{
    
    
public:
	int _b = 0;
};
void Func(A* ptr)
{
    
    
	// 直接转换是不安全的
	B* bptr = (B*)ptr;
	cout << bptr << endl;
}
int main()
{
    
    
	A aa;
	B bb;
	Func(&aa);
	Func(&bb);
	return 0;
}

The func function uses the parent class to receive, but we can convert the type of the parent class into the type of the subclass without reporting an error. For example, the following code: Then a problem may arise at this time, the object of the
Insert image description here
subclass There are both parent class content and subclass content. If the subclass type points to the parent class content, will we inadvertently have out-of-bounds access? For example, the following code:

void Func(A* ptr)
{
    
    
	// 直接转换是不安全的
	B* bptr = (B*)ptr;
	cout << bptr << endl;
	bptr->_a++;
	bptr->_b++;
	cout << bptr->_a << endl;
	cout << bptr->_b << endl;
}

Insert image description here
You can see that there is a problem here, so if ptr points to a subclass object, then there is no problem in converting back to the subclass type. If ptr points to a parent class object, then converting to a subclass object may cause out-of-bounds access. Risk, so this time there is dynamic_cast. Dynamic_cast can only be used for classes whose parent class contains virtual functions (remember that the parent class must have virtual functions), and dynamic_cast will first check whether the conversion can be successful. If it is successful, the conversion cannot be successful. Returns 0, so we can add an if to make a judgment. If the value of bptr is not empty, it means the conversion is successful. If it is empty, it means the conversion failed and will not let it execute the statement inside. Then the code here is as follows:

void Func(A* ptr)
{
    
    
	// 直接转换是不安全的
	B* bptr = dynamic_cast<B*>(ptr);
	cout << bptr << endl;
	if (bptr)
	{
    
    
		bptr->_a++;
		bptr->_b++;
		cout << bptr->_a << endl;
		cout << bptr->_b << endl;
	}
}

The result of running the code is as follows:
Insert image description here

Guess you like

Origin blog.csdn.net/qq_68695298/article/details/131625182