Pregunta

Estoy en lo cierto al suponer que los moldes de tipo C (que están desanimados) no son más que reinterpret_casts? El uso de este último llama la atención visual y fácil para buscar en la búsqueda de moldes desagradables, y por lo tanto se recomienda sobre moldes de tipo C?

Si arrojando const utilizando const_cast y escribir en un objeto originalmente const no está definido, ¿cuál es el propósito de const_cast?

Nota: Sé que Bjarne condena con razón, las operaciones de colada que no sean seguros e incluso llega al extremo de afirmar "Un fea operación debe tener una forma sintáctica feo. " y por lo tanto el nivel de detalle de fundición operadores en C ++. Así que voy a tratar de minimizar su uso. Promesa. :)

¿Fue útil?

Solución

No. Un molde de C puede hacer el equivalente de un const_cast, un static_cast, un reinterpret_cast, o una combinación de los mismos. En caso de que no era más que suficiente, también se puede hacer por lo menos un truco menor que no combinación de los modelos más nuevos pueden hacerlo en absoluto!

Puede utilizar const_cast con resultados definidos si la variable original se define sin const, pero todo lo que tienes es un puntero o const referencia a ese objeto. Otoh, si usted piensa que tiene una buena razón para utilizar un const_cast, lo más probable es que realmente debería mirar hacia arriba mutable lugar.

Editar: supongo que debería haberlo dicho de inmediato, sino una conversión de estilo C se puede convertir en una clase base inaccesible. Por ejemplo, considere algo como:

[Editar: Estoy actualizando el código para algo que va a compilar y (generalmente) demuestran problema. ]

#include <iostream>

class base1 {
public:
    virtual void print() { std::cout << "base 1\n"; }
};

class base2 {
public:
   virtual void print() { std::cout << "base 2\n"; }
};

class derived : base1, base2 {}; // note: private inheritance

int main() {    
    derived *d = new derived;
    base1 *b1 = (base1 *)d;    // allowed
    b1->print();    // prints "base 1"
    base2 *b2 = (base2 *)d;    // also allowed
    b2->print();    // prints "base 2"

//    base1 *bb1 = static_cast<base *>(d);  // not allowed: base is inaccessible

    // Using `reinterpret_cast` allows the code to compile.
    // Unfortunately the result is different, and normally won't work. 
    base1 *bb2 = reinterpret_cast<base1 *>(d);
    bb2->print();   // may cause nasal demons.

    base2 *bb3 = reinterpret_cast<base2 *>(d); 
    bb3->print();   // likewise
    return 0;
}

El código utilizando los reinterpret_casts compilará - pero de intentar utilizar el resultado (de al no sea uno de los dos) causará un problema importante. El reinterpret_cast toma la base de dirección del objeto y los intentos de tratarlo como si fuera el tipo especificado de objeto base derivada - y puesto que (como máximo) objeto de una base de hecho puede existir en esa dirección, intentar tratarlo como la otra lata / causará grandes problemas. Editar: En este caso, las clases son esencialmente idénticos, excepto por lo que se imprimen, por lo que aunque nada podría suceda, la mayoría de los compiladores, ambos de los dos últimos imprimirá 1 "de base". El reinterpret_cast toma cualquier cosa que esté en esa dirección y trata de usar como el tipo especificado. En este caso, he (intentado) hacen que haga algo inofensivo, pero visible. En código real, el resultado probablemente no será tan bonito.

La conversión de estilo C funcionará como un static_cast haría si el código se había utilizado la herencia público en lugar de privado - es decir, que es consciente de dónde en la clase derivada de cada objeto de la clase base "vidas" y ajusta el resultado, por lo que cada puntero resultante va a funcionar porque se ha ajustado a punto en el lugar correcto.

Otros consejos

No, moldes de tipo C puede actuar como reinterpret_casts, const-casts o static_casts dependiendo de la situación. Es por eso que no se animan - ves una conversión de estilo C en código y necesidad de buscar detalles para ver lo que va a hacer. Por ejemplo:

const char* source;
int* target = (int*)source;// - acts as const_cast and reinterpret_cast at once
//int* target = retinterpret_cast<int*>source;// - won't compile - can't remove const

Recuerde que un elenco const puede estar actuando en algo que no sea el identificador original:

void doit(const std::string &cs)
{
    std::string &ms = const_cast<std::string &>(cs);
}

int main()
{
    std::string s;
    doit(s);
}

Así, mientras que doit se Desechar const, en este ejemplo la cadena subyacente no es un comportamiento const por lo que no indefinido.

Actualizar

Bueno, aquí está un mejor ejemplo de cuando se utiliza const_cast no es completamente inútil. Comenzamos con una clase base con una función virtual que toma un parámetro const:

class base
{
public:
    virtual void doit(const std::string &str);
};

y ahora se quieren anular dicha función virtual.

class child : public base
{
public:
    virtual void doit(const std::string &str)
    {
        std::string &mstr = const_cast<std::string &>(str);
    }
};

Debido a la lógica / estructura de su código, usted sabe que child::doit es llamado solo con cuerdas no constante (y class base no está bajo su control, de modo que no se puede modificar ni se puede cambiar la firma de child::doit porque entonces no será ya anular base::doit). En este caso, es seguro que desechar const.

Sí, esto es arriesgado. Tal vez cuando se escribe eso, es cierto que la ejecución nunca alcanzará child::doit con una cadena no constante y el código es válido. Pero eso podría cambiar, ya sea manteniendo al mismo tiempo su programa o tal vez cuando vuelve a generar y recoger la versión más reciente de class base.

const_cast se utiliza para eliminar const de un tipo. También puede eliminar volatile. Si el objeto está muy const entonces el resultado no se puede escribir en el comportamiento y todavía ser bien definido. Sin embargo, si se promueve a const (al ser pasado a una función const T, entonces const_casting de nuevo a no const está bien. (He encontrado alguna información más aquí )

reinterpret_cast no pueden const quitar o volatile de un tipo.

consulta

moldes de tipo C son realmente el martillo de programación - que, básicamente, le dice al compilador que la clavija cuadrada de allí se ajuste a través de este agujero redondo no importa qué. En ese sentido, reinterpret_cast es muy similar.

La principal ventaja que veo en el uso de C ++ - operadores de conversión son de estilo que le permiten expresar su intención de mejorar y permitir que el compilador todavía a algunas comprobaciones sobre la operación que está pidiendo a realizar en lugar de la de uno talla única para todos elenco estilo C.

En cuanto a const_cast- a menudo se tiene en la situación en la que estás pasando a través de un objeto alrededor de referencia constante, simplemente porque la API que requiere para hacer esto. Por ejemplo, usted tiene la función X que las tareas de una cadena de estilo C:

void X(const char *str) { ... }

Dentro de esa función que está pasando el parámetro a una función C que espera un char *, a pesar de que no está cambiando la cadena. La única manera de acomodar esto sería str const_cast.

Yo tendría mucho cuidado usando cualquier tipo de molde, a menudo esto demuestra que hay algo que no está bien con su diseño, pero a veces hay que convencer al compilador que la clavija que está mirando no es tan cuadrado como se supone . Sólo entonces se debe utilizar los operadores de conversión.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top