C ++ | | Cuatro conversiones de tipo forzado (análisis)

Cuatro tipos de coerción


1. La razón

Hay dos tipos de conversión de tipo forzada en lenguaje C.

  1. Conversión de tipo implícita

  2. Reparto de pantalla

Por ejemplo:

int main()
{
    int i = 1;
    double d = i;//隐式类型转换
    int* p = &i;
    int address = (int)p;//显示强制类型转换
    return 0;
}

defecto:

  • La visualización de la conversión es relativamente pobre, para la conversión de tipo implícita

  • Porque todas las formas de conversión están escritas en tipo (), pero el grado no es alto

Entonces, para C ++, para mejorar la visibilidad de la conversión de tipos , hay cuatro tipos de conversión de tipos forzada

Puede determinar directamente qué tipo de conversión se realiza según el nombre.

2. ¿Cuáles son los cuatro tipos de conversión?

1. static_cast

Función: se utiliza para la conversión entre tipos no polimórficos (conversión estática) , equivalente a la conversión de tipo implícita en lenguaje C

Desventajas: no se puede utilizar para la conversión entre dos tipos no relacionados . Por ejemplo: conversión de tipo int a tipo int *

Por ejemplo:

int main()
{
    int i = 1;
    double d = static_cast<double>(i);
    std::cout << d << std::endl;
    retrun 0;
}

2. reinterpret_cast

Rol: convierte un tipo en otro . Es equivalente a mostrar conversión de tipo forzada en lenguaje C

Desventajas: para la conversión aleatoria de datos, habrá problemas impredecibles. Trate de no usar

Por ejemplo:

int main()
{
    int i = 10;
    int* p = &i;
    int j = reinterpret_cast<int>(p);
    return 0;
}

3. const_cast

Rol: eliminar el atributo const de la variable para facilitar la asignación

Desventajas: debido a la optimización del compilador, al acceder a la variable tipo const, no se puede acceder en tiempo real. Es posible que el valor de la memoria haya cambiado, pero se sigue accediendo a los datos antiguos.

Solución: utilice la palabra clave volátil para garantizar la visibilidad de la memoria y vaya directamente a la memoria para obtener los datos cada vez que se acceda a ellos.

Por ejemplo:

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

4. dynamic_cast

Función: se utiliza para convertir un puntero de un objeto de clase principal en un puntero o referencia a un objeto de subclase

Desventajas: cuando el puntero de la clase principal apunta originalmente al objeto de la clase principal, después de la conversión, cuando se utiliza el puntero del tipo de subclase para la operación, puede provocar que el acceso a la memoria esté fuera de los límites

Mejora: solo cuando el puntero de la clase principal apunta al objeto de la subclase, use dynamic_cast para forzar la conversión de tipo

Nota:

  1. dynamic_cast solo se puede usar para clases que contienen funciones virtuales

  2. dynamic_cast primero verificará si se puede convertir correctamente, si se puede convertir, se convertirá, si no, devolverá 0

Si el puntero principal apunta al objeto principal, se produce un error y se devuelve 0

Por ejemplo:

class A
{
    public :
    virtual void f(){}
};
​
class B : public A
    {};
​
void fun (A* pa)
{
    // dynamic_cast会先检查是否能转换成功,能成功则转换,不能则返回
    B* pb1 = static_cast<B*>(pa);
    B* pb2 = dynamic_cast<B*>(pa);
    cout<<"pb1:" <<pb1<< endl;
    cout<<"pb2:" <<pb2<< endl;
}
​
int main ()
{
    A a;
    B b;
    fun(&a);
    fun(&b);
    return 0;
}

 

3. El principio subyacente

Hay dos principios subyacentes:

  1. Los datos realmente han cambiado. Se abre un nuevo espacio en la memoria para almacenar nuevos datos. Cuando se utilizan nuevos datos, los datos originales no se verán afectados

  2. Los datos no han cambiado, pero el tipo ha cambiado. Permita que el compilador considere este tipo de datos como otro tipo de datos, pero los datos son legales.

static_cast es el primer tipo:

Según el código anterior:

Se puede ver claramente que las direcciones de los dos datos son diferentes, por lo que se puede abrir un nuevo espacio de memoria para almacenar nuevos datos.

 

reinterpret_cast es el primer tipo:

Según el código anterior:

Puede ver que se ha abierto un nuevo espacio de memoria.

Para la conversión entre tipos de función, se abre una nueva función y se cambia la dirección.

Por ejemplo:

using namespace std;
typedef void(*FUNC)();
int DoSomething(int i)
{
    cout << "DoSomething" << endl;
    return 0;
}
void Test()
{
    //
    // reinterpret_cast可以编译器以FUNC的定义方式去看待DoSomething函数
    // 所以非常的BUG,下面转换函数指针的代码是不可移植的,所以不建议这样用
    // C++不保证所有的函数指针都被一样的使用,所以这样用有时会产生不确定的结果
    //
    FUNC f = reinterpret_cast< FUNC>(DoSomething);
    f();
}
​
int main()
{
    Test();
    return 0;
}

Comprensión: para una función, una función también es una dirección. Al llamar a esta función, solo se requiere el nombre de la función

Puedes ver que las direcciones de los dos ya son diferentes, por lo que han cambiado

 

const_cast es el segundo tipo:

Una cosa a tener en cuenta: const_cast <> debe ser un puntero, una referencia o un puntero a un miembro del tipo de objeto cuando se muestra un cast

Después de la conversión de tipo forzada, no se crean nuevos datos, no se abre ningún espacio para almacenar punteros, el compilador simplemente trata un tipo de puntero como otro tipo de puntero, asegurando la legalidad del código.

Según el código anterior:

Sin agregar volátiles:

Agregar volátil:

 

dynamic_cast es el segundo tipo

Es solo que el puntero ha cambiado y el compilador ha cambiado su interpretación y no ha abierto espacio de memoria para crear un nuevo puntero.

Según el código anterior:

Se puede ver en la figura que cuando el puntero de la clase principal apunta al objeto de la clase principal, cuando se realiza la conversión dynamic_cast, se producirá el error de conversión y devolverá 0, por lo que la primera vez que se emite pb2, el valor de la variable del puntero es todo 0.

Supongo que te gusta

Origin blog.csdn.net/qq_40399012/article/details/89056512
Recomendado
Clasificación