Cosa significa avere un riferimento indefinito a un membro statico?

Ho appena scritto una lezione con alcuni membri di dati statici, ma ora sto ricevendo errori su “riferimenti non definiti”. Perché non funziona? Che cosa sto facendo di sbagliato?

(Nota: Questo è pensato per essere una voce alle FAQ C ++ di Overflow dello Stack . Se vuoi criticare l’idea di fornire una FAQ in questo modulo, allora la pubblicazione su meta che ha dato inizio a tutto questo sarebbe il posto giusto per farlo. quella domanda viene monitorata nella chatroom C ++ , dove l’idea delle FAQ è iniziata in primo luogo, quindi è molto probabile che la tua risposta venga letta da coloro che hanno avuto l’idea.)

Per capire questo, dovresti avere una buona comprensione della compilazione e del collegamento e delle differenze tra dichiarazioni e definizioni .


Considera la seguente class:

//In header file class Example { static bool exampleStaticMember; }; 

Qui, exampleStaticMember è dichiarato ma non definito. Ciò significa che se exampleStaticMember viene utilizzato in un modo che significa che deve avere un indirizzo, allora deve esserci una definizione separata per esso. In generale, nessuna dichiarazione di un membro di dati statici in una definizione di class è una definizione di quel membro.

La dichiarazione richiesta viene solitamente inserita nel file cpp che contiene le altre definizioni per i membri della class. Deve essere nello stesso spazio dei nomi della definizione della class. La definizione in genere assomiglia a:

 //In source file: //This may optionally have an initialiser (eg "= true") bool Example::exampleStaticMember; 

La definizione può essere inserita in qualsiasi file cpp, ma non dovrebbe essere inserita nell’intestazione con la class, poiché è probabile che ciò interrompa la regola della definizione singola .

Come caso speciale, se la variabile membro statica è un integrale const o un tipo di enumerazione, può avere un inizializzatore nella definizione della class:

 //In header file class Example { static const int initialised = 15; }; 

In questo caso, la definizione nel file cpp è ancora richiesta, ma non è consentito avere un inizializzatore:

 //In source file //Note: no initialiser! const int Example::initialised; 

I membri statici che sono stati inizializzati in questo modo possono essere utilizzati in espressioni costanti.

Modelli

Per un membro di dati statici di un modello, le cose sono leggermente diverse. Il membro statico dovrebbe essere definito nell’intestazione insieme al resto della class:

 //In header file template class Example { static int exampleInt; static T exampleT; } template int Example::exampleInt; template T Example::exampleT; 

Ciò funziona perché esiste un’eccezione specifica alla regola di definizione singola per i membri di dati statici dei modelli di class.

Altri usi di statico

Quando la parola chiave static viene applicata a funzioni e oggetti che non sono nell’ambito di una class, può assumere un significato molto diverso.

Quando applicato a oggetti in un ambito di funzione, dichiara un object inizializzato nella prima esecuzione della funzione e che successivamente mantiene il suo valore tra le chiamate di funzione.

Se applicato a oggetti o funzioni nello scope dei nomi (al di fuori di qualsiasi definizione di class o funzione), dichiara oggetti o funzioni con il collegamento interno . Questo utilizzo è deprecato per gli oggetti, in quanto lo spazio dei nomi senza nome fornisce un’alternativa migliore.

Devi istanziare membri statici definiti in un’intestazione in un file .cpp. Per esempio:

 // foo.h class foo { static int X; }; // foo.cpp #include "foo.h" int foo::X = 0;