Type conversion in C++

Table of contents

1. Type conversion in C language

2. C++ mandatory type conversion

2.1、static_cast

2.2、reinterpret_cast

2.3、const_cast

2.4、dynamic_cast


 

1. Type conversion in C language

In C language, if the types of the left and right sides of the assignment operator are different, or the types of formal participants and actual parameters do not match, or the type of the return value is inconsistent with the type of the received return value, type conversion needs to occur. There are two forms in C language Type conversion: implicit type conversion and explicit type conversion.
1. Implicit type conversion: the compiler automatically performs the conversion during the compilation phase. If it can convert it, it will convert it. If it cannot convert it, the compilation will fail.
2. Explicit type conversion: It needs to be handled by the user

Look at the following code to understand:

void Test()
{
    int i = 1;
    // 隐式类型转换(意义相近的类型)
    double d = i;
    printf("%d, %.2f\n", i, d);
    int* p = &i;
    // 显式的强制类型转换(意义相差比较大的类型),此时隐式便会报错
    int address = (int)p;
    printf("%x, %d\n", p, address);
}

The meanings of int and double are relatively close, so implicit type conversion can be used to upgrade int to double type

And address is an integer, p is a pointer, and then the implicit type conversion will make an error, so it must be explicitly cast at this time.

 

 Disadvantage: The visibility of conversion is relatively poor, all conversion forms are written in the same form, and it is difficult to track wrong conversions.

The following scenario is also very disturbing.

void insert(size_t pos, char ch)
{
    size_t _size = 5;
    int end = _size - 1;
    while (end >= pos)
    {
        --end;
    }
}

When pos=0, end will -- until 0, and end will become -1 the last time it enters, and then compare with pos again. At this time, -1<0 does not meet the conditions and should jump out. However, an implicit Type conversion, upgrade end from int (signed) to size_t ( unsigned) , so that -1 becomes 2^32-1, which causes an infinite loop.

Therefore, in order to solve these problems, C++ proposed these four types of mandatory conversion.

2. C++ mandatory type conversion

In order to enhance the visibility of type conversion, standard C++ introduces four named cast operators:
static_cast, reinterpret_cast, const_cast, dynamic_cast.

2.1、static_cast

static_cast is used for conversion of non-polymorphic types (static conversion), any implicit type conversion performed by the compiler can be used static_cast, but it cannot be used for conversion of two unrelated types

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

    int* p = &a;
    //不支持不相关类型转化
    int address = static_cast<int>(p);
}

Just remember that static_cast is mostly used for implicit type conversions.

2.2、reinterpret_cast

The reinterpret_cast operator generally provides a lower-level reinterpretation of the bit patterns of the operands, used to convert one type to a different type.

It can be understood that it can be forced to an unrelated type.

For example, in the above example, static_cast does not support irrelevant type conversion, that is, it cannot convert the pointer p into an int integer. We can use reinterpret_cast instead.

    int* p = &a;
    //支持不相近类型转化
    int address = reinterpret_cast<int>(p);

In this way, when we see static_cast, we know that this is a similar type conversion. Reinterpret_cast knows that it is a non-similar type conversion.

2.3、const_cast

The most common use of const_cast is to delete the const attribute of a variable for easy assignment.

int main()
{
    const int a = 2;
    //错误的,由于a具有常性
    //int* p = reinterpret_cast<int*>(&a);
    int* p = const_cast<int*>(&a);
    *p = 3;
}

Using const_cast, the address of the constant a is successfully given to p at this time, and then it can be modified.

But there is a strange phenomenon:

We output the values ​​of a and *p. Since the address of p is also a, modifying p will also affect a.

So our expected result should be 3. Let's output:

    cout << a << endl;
    cout << *p << endl;

The answer is 2 and 3. Why is a not modified? Let's debug and observe:

 

 The strange phenomenon appeared again, the display of a in the memory has also been changed to 3, why is the output still 2?

This is due to the optimization of the compiler. The compiler thinks that a is const and cannot be changed. So every time I fetch it from memory, the compiler will directly load a into the register , and read directly from the register every time. , the efficiency will increase. Because it is const, I can't write it, so I dare to put it in the register. So every time I read it is the first 2.

As for the monitoring window, it is also another separate process, not optimized, but detected in real time, it will go to the memory to fetch it at this time, and it will display 3.

Then if we don't want the compiler to optimize, we have to fetch it from memory every time, then we need to add the volatile keyword in front.

This time the correct result is obtained.

The following transformation is unique to C++.

2.4、dynamic_cast

dynamic_cast is used to convert a pointer/reference of a parent class object to a pointer or reference of a subclass object (dynamic conversion)
upward transformation: subclass object pointer/reference -> parent class pointer/reference (no conversion required, assignment compatibility rules)

Downcast: parent class object pointer/reference -> child class pointer/reference ( dynamic_cast transformation is safe)
Note: 1. dynamic_cast can only be used for classes with virtual functions 2. dynamic_cast will first check whether the conversion is successful, If successful, the conversion is successful, and if not, nullptr is returned.

Look at this code:

class A
{
public:
    int _a = 0;
};
class B : public A
{
public:
    int _b = 1;
};
int main()
{
    B bb;
    //子类->父类
    A aa1 = bb;
    A& ra1 = bb;
}

The above can be converted normally. When the subclass is converted into the parent class, there will be slice operations, which we can understand.

But in the downward transformation, when the parent class is transformed into a subclass, can it be converted normally?

The first thing to know is that the parent class object cannot be transformed into a subclass object anyway.

But using dynamic_cast can convert the pointer or reference of the parent class object to the pointer or reference of the subclass.

class A
{
public:
    virtual void f() {}
};
class B : public A
{};
//A*指针有可能指向父类,有可能指向子类
void fun(A* pa)
{
    // dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回0
    //如果pa是指向子类,那么可以转化,转化表达式返回正确的地址
    //如果pa是指向父类,那么不可以转化,转化表达式返回nullptr
    B* pb = dynamic_cast<B*>(pa);//安全的
    //B* pb = (B*)pa;//不安全的,都会转化成功
    if (pb)
    {
        cout << "转化成功" << endl;
    }
    else
    {
        cout << "转化失败" << endl;
    }
}
int main()
{
    A a;
    B b;
    fun(&a);
    fun(&b);
    return 0;
}

In general: The real function of dynamic_cast is to distinguish whether the pointer points to the parent class or the child class.

If the "parent class" pointer is a parent class pointer, an error will occur when dynamic_casting to a subclass.

If the "parent" pointer is a subclass pointer, the dynamic_cast to subclass will succeed.

So dynamic_cast downcasting is safe.

In this way, the four types of conversion of C++ are all finished.

Guess you like

Origin blog.csdn.net/weixin_47257473/article/details/131666528