2012-06-20 13 views
13

Según Scott Meyers, para evitar la repetición del código en la versión const de un getter y la versión no const de un getter, llame a la versión const del método de la versión no const: static_cast<const A&>(*this).Methodology();sin embargo,, en accidental uso debido a un exceso de visión Visual Intellist X Intellisense escribí: const_cast<const A&>(*this).Methodology(); y funcionó bien.C++ ¿diferencia entre agregar const-ness con static_cast y const_cast de "este" objeto?

¿Cuáles son todas las diferencias en este caso con el uso de un modelo en particular?

IDE en uso: Visual Studio 2010.

+1

Me pregunto por qué Scott promueve el uso de static_cast, mientras que const_cast parece una opción más adecuada aquí, también expresa más claramente la intención? ¿O no lo estás usando exactamente de la manera en que se refería? – stijn

+0

@stijn: Me he preguntado lo mismo también. 'const_cast' se siente un poco más natural para mí, incluso para la dirección más segura de agregar' const'. –

+0

@CharlesBailey: vea mi respuesta para ver por qué no promocionó uno sobre el otro. – Casey

Respuesta

5

Suponiendo que el tipo de this es A*, no hay ninguna diferencia.

En general const_cast pueden lanzar tiendas de comida para el const especificador (desde cualquier nivel de indirección o parámetro de plantilla)

static_cast<> puede emitir un tipo a otro si el tipo de objetivo está en jerarquía de tipos de la fuente.

No pueden hacer el trabajo de los demás.

La razón por la que ambos trabajaban en su caso es porque tiene introdujo const-dad, en lugar de haber quitado (llamando desde la versión no constante de la función del tipo de this es A*, sin const) También podría haber escrito

const A& tmp = *this; 
tmp.Methodology(); 

y hubiera funcionado sin necesidad de ningún tipo de fundición. El lanzamiento se usa por comodidad y precisión para no tener que introducir una nueva variable.

Nota: se puede usar static_cast<> aquí, ya que sabe que se está lanzando al tipo correcto. En otros casos (cuando no se puede estar seguro) es necesario utilizar dynamic_cast<> que hace una verificación de tipos en tiempo de ejecución para garantizar la conversión es válida

+0

'A' es un tipo de clase,' this' viene por defecto a 'const * A'. – Casey

+0

@Casey - Me di cuenta de eso; el punto era que es la clase donde se hace esto, no por ejemplo una subclase (en cuyo caso el 'const_cast <>' habría fallado) – Attila

+1

@Casey - el tipo de 'this' es' const A * '(más precisamente 'const A * const') si está en una función de miembro' const', de lo contrario es 'A *' (más precisamente 'A * const') – Attila

3

Después de volver a la lectura del artículo 3 de Effective C++ 3rd Ed. Soy consciente de que en realidad estaba abogando por el uso de tanto . Agregue const para llamar a la versión de const, luego descartar la const-ness del valor de retorno (si hay uno). En mi caso particular, no hay valor de retorno constante, sólo una función const por lo que la envuelta por const_cast <> versión no es necesario y de hecho provoca que haya ninguna diferencia entre las dos llamadas en cuestión

(pág. 13) Tema 3: usoconstsiempre que sea posible

...

(p.23) evitar la duplicación deconstyno- constfunciones miembro

... Lo que realmente quiere hacer es aplicar operador [] funcionalidad una vez y utilícelo dos veces. Es decir, si desea tener una versión del operador [], llame al otro. Y eso nos lleva a desechar la constness.

... Desechar los const en el valor de retorno es seguro, en este caso, porque quien llama el operador no const [] debe haber tenido una constante objeto no en el primer lugar .... Así que tener la const no operador [] llamar a la versión const es una manera segura de evitar la duplicación de código , a pesar de que requiere un molde ...

class TextBlock { 
public: 

... 

    const char& operator[](std::size_t position) const  //same as before 
    { 
     ... 
     ... 
     ... 
     return text[position]; 
    } 

    char& operator[](std::size_t position)  //now just calls const op[] 
    { 
     //cast away const on op[]'s return type; 
     //add const to *this's type; 
     //call const version of op[]. 
     return const_cast<char&>(static_cast<const TextBlock&>(*this)[position]); 
    } 
... 
}; 

Como puede ver, el código tiene dos moldes, no uno. Queremos que el no operador const [] ... Para evitar la repetición infinita, tenemos que especificamos que queremos llamar al operador const [], pero no hay forma directa de hacer eso. En su lugar, echamos * este de su tipo nativo de TextBlock & a const TextBlock &. Sí, usamos cast para agregar const! Así que tenemos dos moldes: uno para añadirlo const a * este (de modo que nuestro llamado a operador [] llamará al const versión), la segunda a quitar el const del * const el valor de retorno del operador [].

Cuestiones relacionadas