Pregunta

Me gustaría preguntar si el uso de mutable es apropiado en este caso:

#include <iostream>

class Base
{
protected:
  int x;

public:
  virtual void NoMod() const
  {
    std::cout << x << std::endl;
  }
  void Draw() const
  {
    this->NoMod();  
  }
};

class Derive : public Base
{
private:
  mutable int y;

public:
  void NoMod() const
  {
    y = 5;
  }
};

int main()
{
  Derive derive;

  // Test virtual with derive
  derive.Draw();

  return 0;
}

La clase base es una biblioteca tercera parte. Les extiendo a ofrecer mi propia NoMod (). El NoMod original de la biblioteca () se declara como const.

Mi NoMod () difiere de la base en el hecho de que se necesita modificar su propia variable miembro.

Por lo tanto, para mi propia NoMod () para compilar y ser llamado cuando Draw () se llama, que tenía que

1) Implementar Derivar :: NoMod () como un const
2) hacer mi int y mutable.

¿Es esto lo mejor que puedo hacer?

¿Fue útil?

Solución

Como 'cabeza friki' descrito, la respuesta a su pregunta depende de cómo se utiliza su miembro de datos.

distingo dos tipos de miembros de datos en una clase.

Yo uso el término común 'atributo' para referirse a los miembros de datos que son el estado lógico o 'valor' del objeto. Normalmente atributos rara vez se declaran como mutable.

He acuñado el protologism 'contribuir' que denotan miembros de datos que son simplemente 'trabajo de memoria / almacenamiento' y que están divorciados algo del estado del objeto. Contribuye no tienen relevancia contextual para el usuario del objeto, existen en la clase sólo para contribuir al mantenimiento y la operación eficiente del objeto. Contribuye se declaran por lo general en la clase como mutable y son siempre privada o protegida.

Por ejemplo digamos que su objeto es una lista enlazada, por lo que tiene un puntero al primer elemento de la lista. Me parece que es un puntero contribuir a causa no representa los datos de la lista. Incluso si la lista está ordenada y la puntero se sitúa en el nuevo primer elemento de la lista, el usuario del objeto de lista le importa cómo el Se mantiene la lista. Sólo que los datos de lista tiene ha modificado o no y que el la lista está ordenada o no es, correspondiente a la perspectiva del usuario. Aún si tiene un miembro de datos booean 'ordenados' para determinar rápidamente si la lista está en un estado ordenado, eso también sería un aporte porque es la estructura de la lista en sí, que impregna el estado ordenado, el 'ordenados' miembro variable se utiliza simplemente para recordar de manera eficiente el estado sin tener que escanear la lista.

Como otro ejemplo, si usted tiene un método const que busca en la lista. Supongamos que se sabe que por lo general la búsqueda devolverá el más recientemente previamente buscado artículo, guardarías un puntero en su clase a un elemento, por lo que su método primero puede comprobar si el último elemento encontrado coincide con la clave de búsqueda antes de buscar toda la lista (si el método en efecto, hay que buscar en la lista y se encuentra un elemento, el puntero se actualizaría). Este puntero que consideraría como un aporte porque sólo está allí para ayudar a acelerar la búsqueda. A pesar de Búsqueda actualiza el puntero de contribuir, el método es efectiva const porque ninguno de los datos de los ítems en el contenedor se modifican.

Por lo tanto, los miembros de datos que son atributos no suelen ser declarado mutable, y los datos de los miembros que contribuyen al funcionamiento de un objeto por lo general será mutable.

Otros consejos

Es difícil de decir, ya que no da ningún contexto en lo que se refiere a y o cómo se utiliza.

En general, mutable sólo es apropiada cuando se cambia la variable mutable no cambia el "valor" real del objeto. Por ejemplo, cuando estaba escribiendo un contenedor para cuerdas de tipo C, que necesitaba para hacer la variable interna mLength mutable para que pudiera almacenar en caché el largo, incluso si lo que se solicitó el era un objeto const. No lo hizo Cambio o la longitud de la cadena, y no era visible fuera de la propia clase, por lo que lo que es mutable estaba bien.

La única vez que pienso mutable está bien es para cosas como cuentas de referencia que no son realmente parte del estado del objeto.

Si y es parte de del objeto física estado, pero no lógica estado, entonces esto está bien, pero por lo demás, no lo hacen.

Utilice mutable cuando el miembro de la clase no es realmente definir el estado del objeto, (por ejemplo, es un valor / objeto en caché que ayuda a mejorar el rendimiento).

que utilizo para hacer otra diferencia. En el ejemplo, sólo se hace cumplir a cambio de objeto constante sólo una vez. Puede utilizar operador también const_cast:

const_cast< Derive*>( this)->y = 10;

Cuando se utiliza el operador const_cast, usted tiene la ventaja de que se puede identificar fácilmente a los lugares donde se aplicó la const a la conversión no constante simplemente ejecutando una búsqueda en su código para el nombre del operador.

Sin embargo, como dije, si el miembro no es parte del estado del objeto, sino que debe ser cambiado indirectamente en varios métodos constantes, utilice mutable para ese miembro.

Las únicas situaciones en las que necesitaba la función mutable son:

  • una versión en caché de los datos derivados. Por ejemplo, si usted tiene una clase rectángulo que tiene una función miembro GetSurface () que es probable que se llamará mucho, usted podría agregar una variable miembro mutable m_surfaceCache para mantener los datos derivados.
  • una variable crítica de miembros de sección. Esto se debe a mi Sección Crítica :: Enter () es conceptualmente no const, pero la variable crítica miembro de sección no es una parte real de los datos de la clase, es más como una guía compilador.

Sin embargo, como regla general, I'dd aconsejan no utilizar mutable demasiado a menudo, ya que no pasa por función const maravillosa C ++ 's.

Otra situación en la que se pueda imaginar 'mutable' es cuando usted tiene una clase con variables miembro 'const' y que necesita para implementar el operador de asignación (=), sin saltarse la asignación del miembro 'const'.

Además, const_cast apllied sobre declarada originalmente 'const' variable y usarlo es U.B. según la norma C ++. Así que si la interfaz de un método acepta un 'const', que tiene que ser modificado internamente, pasarla a un argumento 'mutable'.

Es posible juzgar la adecuación de la misma a partir de las situaciones anteriores es decir, sólo tiene sentido semántico! No lo utilice para hacer la compilables-código fuente.

Saludos,

Si, como usted ha dicho, es parte de una biblioteca de terceros, puede que no tenga una opción. C ++ es en el fondo un lenguaje pragmático y le permite hacer lo que tiene que hacer, aunque no siempre sea una "mejor práctica".

Una cosa a destacar, sin embargo, es que la biblioteca de terceros que está documentando NoMod no debe modificar el objeto añadiendo que especificador const. Al violar el contrato, usted se deja abierto a posibles problemas. Si la biblioteca en algunas situaciones llamar NoMod varias veces, su clase derivada mejor que sea capaz de manejar eso, ya que un verdadero método const no tendría ningún problema con él.

Me primero busco otra forma de resolver el problema, pero no hay declaro mutable.

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