2009-12-21 20 views
8

Sto cercando di decidere quale sarebbe l'opzione migliore quando un oggetto ha alcuni tratti che non cambieranno e sono necessari in tutte le sue funzioni.Membri privati: Statico const vs. just const

  1. membri static const
  2. membri Const

Mi sembra come il vero motivo di un membro statico è quello di avere una variabile che può essere modificata, e influenzano in tal modo tutti gli altri oggetti del stessa classe. Tuttavia, ho avuto persone che raccomandano gli "invarianti" di classe per essere membri const statici. Sto cercando alcune informazioni sull'approccio raccomandato per stabilire le costanti di classe e le ragioni per le quali.

risposta

15

"Non cambierà" non è abbastanza preciso. La domanda principale qui è se i diversi oggetti della classe debbano avere valori diversi di questi membri const (anche se non cambiano durante la vita dell'oggetto) o tutti gli oggetti dovrebbero usare (condividere) lo stesso valore.

Se il valore è lo stesso per tutti gli oggetti della classe, allora, ovviamente, dovrebbe essere un membro della classe static const.

Se diversi oggetti potrebbero richiedere valori diversi, è necessario che sia un membro non statico const.

+0

By "non cambierà" Intendevo il valore è lo stesso per tutti gli oggetti della classe. – trikker

+3

In questo caso non hai motivo di non renderlo 'static const'. Anche un const non statico funzionerà (a parte alcuni casi specifici/esotici), ma comporterà inutili sprechi di memoria. – AnT

+0

Sì, questo è l'essenza che ho ottenuto. – trikker

14

Un membro const deve essere utilizzato quando quel membro non cambia in base all'istanza. Un membro static const deve essere utilizzato quando quel membro non cambia in base alla classe. In altre parole, indipendentemente dal numero di istanze create, il membro static const rimane fisso tra tutte le istanze mentre il membro const è costante solo per un'istanza specifica.

Non sono sicuro che sia quello che stai cercando dato che è solo una spiegazione di come si comportano, ma spero che sia di aiuto.

+0

Precisamente spiegato. –

1

Un motivo potrebbe essere che i membri const regolari occuperanno più memoria ... ad esempio, per ciascun oggetto della classe che crei, un oggetto membro const verrà incluso in quell'oggetto e inizializzato.

Se è un membro const statico, d'altra parte, solo un oggetto verrà creato e inizializzato, indipendentemente dal numero di oggetti della classe che crei e tutti gli oggetti di classe condivideranno lo stesso oggetto.

Per dimostrare, prova a compilarlo in entrambi i modi, creando diversi oggetti e facendo un printf ("% p", & theConstMemberObject) ... quando è statico, vedrai che tutti stampano lo stesso valore del puntatore; quando non è statico, ognuno ha il proprio oggetto e quindi ognuno di essi stampa un valore di puntatore diverso.

0

Si renderebbe un membro const const statico perché, essendo invariato, è possibile riutilizzare la stessa copia di esso, condivisa da tutte le istanze della classe. A differenza di ogni istanza con la sua copia (identica) del valore costante.

Ci si aspetterebbe che il compilatore fosse abbastanza intelligente da fare questa ottimizzazione per te, e ho il sospetto che lo faccia. Però è una buona abitudine entrare.

+2

Una variabile membro const può essere inizializzata nel costruttore, pertanto può variare a seconda delle istanze della classe. – danio

+1

Devi stare attento a ciò che puoi assumere dal compilatore per te. Come fa notare @danio, se l'intestazione viene riutilizzata in diverse unità di compilazione, esiste una sola unità di compilazione in cui il compilatore può sapere che il valore è condiviso, al contrario di molti che devono definire un layout di memoria compatibile. Quello che sa, non può cambiare il layout della memoria in quanto si romperà il codice in tutte le altre unità di compilazione. –

0

la mia preferenza non è quella di utilizzare i membri static const poiché sembra sempre che creino più accoppiamenti dei membri const; a volte confusione w.r.gerarchia t diamante ereditarietà dove la classe finale eredita dalle classi 2 Super (1 classe viene ereditata public, l'altro è ereditata virtual public) definendo quindi un membro static const che indica una regione di memoria dinamica tramite new, malloc, calloc ecc comporterebbe un double free errore.

ad es. ecco l'output di una situazione eredità semplice diamante di

ray:~ ray$ ./multiinheritance 
Base() called 
Derived1() called 
Base() called 
Derived2() called 
Final() called 
~Final() called 
~Derived2() called 
~Base() called 
freeing memory 
~Derived1() called 
~Base() called 
freeing memory 
multiinheritance(475) malloc: *** error for object 0x100150: double free 
*** set a breakpoint in malloc_error_break to debug 
ray:~ ray$ 

Ecco il codice:

#include <iostream> 
#include <string> 

class Base { 
public: 
    Base() { 
     std::cout << "Base() called " << std::endl; 
    } 
    virtual ~Base() { 
     std::cout << "~Base() called" << std::endl; 
     std::cout << "freeing memory" << std::endl; 
     delete i; 
    } 
    static const int* i; 
}; 

const int* Base::i = new int[5]; 

class Derived1 : virtual public Base { 
public: 
    Derived1() { 
     std::cout << "Derived1() called " << std::endl; 
    } 
    virtual ~Derived1() { 
     std::cout << "~Derived1() called" << std::endl; 
    } 
}; 
class Derived2 : public Base { 
public: 
    Derived2() { 
     std::cout << "Derived2() called " << std::endl; 
    } 
    virtual ~Derived2() { 
     std::cout << "~Derived2() called" << std::endl; 
    } 
}; 

class Final: public Derived1, public Derived2 { 
public: 
    Final() { 
     std::cout << "Final() called" << std::endl; 
    } 
    ~Final() { 
     std::cout << "~Final() called" << std::endl; 
    } 
}; 

int main(int argc, char** argv) { 
    Final f; 
return 0; 
} 
+0

Dovresti pubblicare il codice da cui hai ottenuto quell'output, altrimenti è inutile. E non sono così sicuro che sarebbe comunque utile, dato che non riesco a vedere dove il 'const' vs' static const' farebbe la differenza. Dalla descrizione fornita sembra più un problema con l'allocazione e l'eliminazione della memoria dinamica 'static' vs' non-static'. –

+0

@dribeas, stavo tentando di illustrare che a volte mescolando 'const' e' static const' con l'ereditarietà multipla/virtuale –