Domanda

Vorrei chiedere se l'uso di mutabile è appropriato qui:

#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 classe Base è una libreria di terze parti. Sto estendendolo a fornire il mio NoMod (). Il NoMod originale libreria () è dichiarata come const.

Il mio NoMod () differisce dalla base nel fatto che ha bisogno di modificare la propria variabile membro.

In questo modo, per il mio NoMod () per compilare e ottenere chiamato quando Draw () viene chiamato, ho dovuto

1) Implementare Derive :: NoMod () come
const 2) rendere la mia int y mutevole.

E 'questo il meglio che posso fare?

È stato utile?

Soluzione

Per quanto 'testa disadattato' descritta, la risposta alla tua domanda dipende da come viene impiegato il membro di dati.

I distinguere due tipi di componenti di dati in una classe.

Uso il termine comune 'attributo' per riferirsi ai membri di dati che sono lo stato logico o 'valore' dell'oggetto. In genere gli attributi sono raramente dichiarati come mutabile.

Ho coniato il protologism 'contribuire' si denotano membri di dati che sono semplicemente 'memoria di lavoro / stoccaggio' e che sono alquanto separata dalla stato dell'oggetto. Contribuisce hanno alcuna rilevanza contestuale per l'utente di un oggetto, esistono nella classe solo per contribuire al mantenimento ed efficiente funzionamento dell'oggetto. Contribuisce sono generalmente dichiarati nella classe come mutevole e sono sempre privato o protetto.

Per esempio supponiamo che il tuo oggetto è una lista collegata, in modo da avere un puntatore al primo elemento della lista. Vorrei prendere in considerazione questo puntatore a contribuire perché non rappresenta i dati nella lista. Anche se la lista è ordinata e la puntatore viene spostato alla nuova prima voce della lista, l'utente dell'oggetto lista potrebbe fregare di meno come il lista è mantenuta. Solo che i dati lista ha stato modificato o meno e che la la lista è ordinata o non è rilevante per punto di vista dell'utente. Anche se si ha un membro dati booean 'ordinato' di determinare rapidamente se la lista è in uno stato ordinato, anche questo sarebbe un contributo perché è la struttura della lista stessa che impregna lo stato ordinato, il 'ordinato' membro variabile è usata semplicemente per ricordare in modo efficiente lo Stato senza dover scorrere la lista.

Per fare un altro esempio, se si dispone di un metodo const che cerca la lista. Supponiamo che si sa che in genere la ricerca restituirà la più recentemente la precedente ricerca di voce, si dovrebbe tenere un puntatore nella tua classe a tale voce in modo che il metodo può in primo luogo verificare se l'ultima trovata voce corrisponde alla chiave di ricerca prima di cercare l'intero elenco (se il metodo effettivamente bisogno di cercare la lista e trova un elemento, il puntatore sarebbe stato aggiornato). Questo puntatore vorrei prendere in considerazione per essere un contributo perché è lì solo per contribuire ad accelerare la ricerca. Anche se il Ricerca aggiorna il puntatore contribuire, il metodo è efficace const perché nessuno dei dati le voci nel contenitore vengono modificati.

Quindi, i membri di dati che sono attributi sono di solito non dichiarati mutevole, e dati membri che contribuiscono al funzionamento di un oggetto di solito è mutevole.

Altri suggerimenti

E 'difficile da dire, dal momento che non si dà alcun contesto di ciò che si riferisce a y o come viene usato.

In generale, mutable è appropriato solo quando si modifica la variabile mutabile non cambia il "valore" reale dell'oggetto. Per esempio, quando stavo scrivendo un wrapper per le stringhe C-style, avevo bisogno di fare la variabile mLength interna mutabile in modo da poter memorizzare nella cache la lunghezza, anche se la cosa è stato chiesto su era un oggetto const. Essa non ha Modifica la lunghezza o la stringa, e non era visibile al di fuori della classe stessa, in modo che lo rende mutable andava bene.

L'unica volta che penso mutable va bene è per cose come il numero di riferimenti che non sono realmente parte dello stato dell'oggetto.

Se y fa parte dell'oggetto fisico Stato, ma non logico Stato, allora questo va bene, ma per il resto, non farlo.

Utilizzare mutabile quando il membro della classe non è realmente che definiscono lo stato dell'oggetto, (ad esempio, è un valore / oggetto in cache che aiuta a migliorare le prestazioni).

io uso per fare un'altra differenza. Nel tuo esempio, a far rispettare unico cambiamento a const oggetto una sola volta. È possibile utilizzare anche operatore di const_cast:

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

Quando si utilizza operatore const_cast, si ha il vantaggio che si può facilmente individuare i luoghi in cui si Enforced il const alla conversione non-const semplicemente eseguendo una ricerca nel codice per il nome dell'operatore.

Tuttavia, come detto, se l'utente non è parte dello stato dell'oggetto, ma deve essere cambiato indirettamente in vari metodi continui, utilizzare mutevole per questo utente.

Le uniche situazioni in cui avevo bisogno la caratteristica mutevole sono:

  • una versione cache dei dati derivati. Ad esempio, se si dispone di una classe Rectangle che ha una funzione membro GetSurface () che rischia di essere chiamato un sacco, si potrebbe aggiungere una variabile mutabile membro m_surfaceCache per mantenere i dati derivati.
  • una variabile membro sezione critica. Questo è perché il mio CriticalSection :: Invio () è concettualmente non const, ma la variabile membro sezione critica non è un vero e proprio parte dei dati di classe, è più come una linea guida compilatore.

Tuttavia, come regola generale, I'dd consigliare di non usare troppo spesso mutevole, in quanto ignora caratteristica meravigliosa const C ++ 's.

Un'altra situazione in cui si può pensare 'mutabile' è quando si ha una classe con variabili 'const' membri e si richiede di implementare l'operatore di assegnazione (=) senza saltare l'assegnazione del membro 'const'.

Inoltre, const_cast apllied sulla originariamente dichiarato 'const' variabile e usarlo è U.B. secondo lo standard C ++. Quindi, se l'interfaccia di un metodo accetta un 'const' che deve essere modificato internamente, passare un argomento 'mutevole'.

Si può valutare l'adeguatezza dello stesso dalle situazioni di cui sopra vale a dire solo di ha senso semanticamente! Non utilizzarlo per rendere il codice sorgente compilabile.

Saluti,

Se, come hai detto, è parte di una libreria di terze parti, non si può avere una scelta. C ++ è in fondo un linguaggio pragmatico e permette di fare ciò che è necessario fare, anche se non può essere sempre una "best practice".

Una cosa da notare, però, è che la libreria di terze parti è documentare che NoMod non dovrebbe modificare l'oggetto con l'aggiunta che specificatore const. Violando tale contratto, si lascia te aperto a possibili problemi. Se la libreria in alcune situazioni richiedono NoMod più volte, la vostra classe derivata meglio essere in grado di gestire che, dal momento che un vero metodo const non avrebbe alcun problema con esso.

Prima di tutto avrei cercare un altro modo per risolvere il problema, ma non riuscendo là dichiaro mutevole.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top