Per chiarire la domanda, preferirei categorizzare l'uso della parola chiave "statica" in tre forme diverse:
(UN). variabili
(B). funzioni
(C). variabili / funzioni dei membri delle classi
la spiegazione seguente segue per ciascuna delle sottorubriche:
(A) parola chiave "statica" per variabili
Questo può essere un po 'complicato, tuttavia, se spiegato e compreso correttamente, è piuttosto semplice.
Per spiegarlo, in primo luogo è davvero utile conoscere l' ambito, la durata e il legame delle variabili, senza le quali le cose sono sempre difficili da vedere attraverso il concetto oscuro di parola chiave staic
1. Ambito : determina dove è accessibile la variabile nel file. Può essere di due tipi: (i) Ambito locale o di blocco . (ii) Ambito globale
2. Durata : determina quando una variabile viene creata e distrutta. Anche in questo caso è di due tipi: (i) Durata di memorizzazione automatica (per variabili con ambito locale o di blocco). (ii) Durata dell'archiviazione statica (per variabili con ambito globale o variabili locali (in una funzione o in un blocco di codice) con identificatore statico ).
3. Collegamento : determina se è possibile accedere (o collegare) a una variabile in un altro file. Anche in questo caso (e per fortuna) è di due tipi: (i) Linkage interno
(per variabili che hanno Block Scope e Global Scope / File Scope / Global Namespace scope) (ii) Link esterno (per variabili che hanno solo Global Scope / File Scope / Ambito globale dello spazio dei nomi)
Facciamo riferimento di seguito un esempio per una migliore comprensione delle semplici variabili globali e locali (nessuna variabile locale con durata dell'archiviazione statica):
//main file
#include <iostream>
int global_var1; //has global scope
const global_var2(1.618); //has global scope
int main()
{
//these variables are local to the block main.
//they have automatic duration, i.e, they are created when the main() is
// executed and destroyed, when main goes out of scope
int local_var1(23);
const double local_var2(3.14);
{
/* this is yet another block, all variables declared within this block are
have local scope limited within this block. */
// all variables declared within this block too have automatic duration, i.e,
/*they are created at the point of definition within this block,
and destroyed as soon as this block ends */
char block_char1;
int local_var1(32) //NOTE: this has been re-declared within the block,
//it shadows the local_var1 declared outside
std::cout << local_var1 <<"\n"; //prints 32
}//end of block
//local_var1 declared inside goes out of scope
std::cout << local_var1 << "\n"; //prints 23
global_var1 = 29; //global_var1 has been declared outside main (global scope)
std::cout << global_var1 << "\n"; //prints 29
std::cout << global_var2 << "\n"; //prints 1.618
return 0;
} //local_var1, local_var2 go out of scope as main ends
//global_var1, global_var2 go out of scope as the program terminates
//(in this case program ends with end of main, so both local and global
//variable go out of scope together
Ora arriva il concetto di collegamento. Quando una variabile globale definita in un file deve essere utilizzata in un altro file, il collegamento della variabile svolge un ruolo importante.
Il collegamento di variabili globali è specificato dalle parole chiave: (i) statico e, (ii) esterno
(Ora ottieni la spiegazione)
la parola chiave static può essere applicata a variabili con ambito locale e globale e in entrambi i casi significano cose diverse. Spiegherò innanzitutto l'uso della parola chiave "statica" nelle variabili con portata globale (dove chiarirò anche l'uso della parola chiave "extern") e successivamente le parole chiave con portata locale.
1. Parola chiave statica per variabili con portata globale
Le variabili globali hanno una durata statica, il che significa che non escono dall'ambito di applicazione quando termina un determinato blocco di codice (ad esempio main ()) in cui viene utilizzato. A seconda del collegamento, è possibile accedervi solo all'interno dello stesso file in cui sono dichiarati (per variabile globale statica) o all'esterno del file anche al di fuori del file in cui sono dichiarati (variabili globali di tipo extern)
Nel caso di una variabile globale con specificatore extern e se si accede a questa variabile all'esterno del file in cui è stata inizializzata, deve essere dichiarata in avanti nel file in cui viene utilizzata, proprio come una funzione deve essere inoltrata dichiarato se la sua definizione si trova in un file diverso da quello in cui viene utilizzato.
Al contrario, se la variabile globale ha una parola chiave statica, non può essere utilizzata in un file al di fuori del quale è stata dichiarata.
(vedi esempio sotto per chiarimenti)
per esempio:
//main2.cpp
static int global_var3 = 23; /*static global variable, cannot be
accessed in anyother file */
extern double global_var4 = 71; /*can be accessed outside this file linked to main2.cpp */
int main() { return 0; }
main3.cpp
//main3.cpp
#include <iostream>
int main()
{
extern int gloabl_var4; /*this variable refers to the gloabal_var4
defined in the main2.cpp file */
std::cout << global_var4 << "\n"; //prints 71;
return 0;
}
ora qualsiasi variabile in c ++ può essere una const o una non const e per ogni 'const-ness' otteniamo due casi di collegamento c ++ predefinito, nel caso in cui nessuno sia specificato:
(i) Se una variabile globale non è const, il suo collegamento è esterno per impostazione predefinita , ovvero è possibile accedere alla variabile globale non const in un altro file .cpp mediante dichiarazione in avanti utilizzando la parola chiave extern (in altre parole, non const global le variabili hanno un collegamento esterno (con durata statica ovviamente)). Anche l'uso della parola chiave extern nel file originale in cui è stata definita è ridondante. In questo caso per rendere inaccessibile una variabile globale non const al file esterno, utilizzare l'identificatore "statico" prima del tipo di variabile .
(ii) Se una variabile globale è const, il suo collegamento è statico per impostazione predefinita , ovvero non è possibile accedere a una variabile globale const in un file diverso da dove è definita, (in altre parole, le variabili globali const hanno un collegamento interno (con durata statica ovviamente)). Anche l'uso di parole chiave statiche per impedire l'accesso a una variabile globale const in un altro file è ridondante. Qui, per fare in modo che una variabile globale const abbia un collegamento esterno, utilizzare l'identificatore 'extern' prima del tipo di variabile
Ecco un riepilogo per le variabili di ambito globali con vari collegamenti
//globalVariables1.cpp
// defining uninitialized vairbles
int globalVar1; // uninitialized global variable with external linkage
static int globalVar2; // uninitialized global variable with internal linkage
const int globalVar3; // error, since const variables must be initialized upon declaration
const int globalVar4 = 23; //correct, but with static linkage (cannot be accessed outside the file where it has been declared*/
extern const double globalVar5 = 1.57; //this const variable ca be accessed outside the file where it has been declared
Successivamente esamineremo come si comportano le variabili globali di cui sopra quando vi si accede in un altro file.
//using_globalVariables1.cpp (eg for the usage of global variables above)
// Forward declaration via extern keyword:
extern int globalVar1; // correct since globalVar1 is not a const or static
extern int globalVar2; //incorrect since globalVar2 has internal linkage
extern const int globalVar4; /* incorrect since globalVar4 has no extern
specifier, limited to internal linkage by
default (static specifier for const variables) */
extern const double globalVar5; /*correct since in the previous file, it
has extern specifier, no need to initialize the
const variable here, since it has already been
legitimately defined perviously */
2. Parola chiave statica per variabili con ambito locale
Aggiornamenti (agosto 2019) su parola chiave statica per variabili nell'ambito locale
Questo ulteriore può essere suddiviso in due categorie:
(i) parola chiave statica per variabili all'interno di un blocco funzione e (ii) parola chiave statica per variabili all'interno di un blocco locale senza nome.
(i) parola chiave statica per variabili all'interno di un blocco funzione.
In precedenza, ho detto che le variabili con ambito locale hanno una durata automatica, cioè diventano esistenti quando si inserisce il blocco (sia esso un blocco normale, sia esso un blocco funzione) e cessano di esistere quando il blocco termina, per farla breve, variabili con ambito locale hanno durata automatica e le variabili di durata automatica (e gli oggetti) non hanno alcun collegamento, il che significa che non sono visibili al di fuori del blocco di codice.
Se l' identificatore statico viene applicato a una variabile locale all'interno di un blocco funzione, cambia la durata della variabile da automatica a statica e la sua durata è l'intera durata del programma, il che significa che ha una posizione di memoria fissa e il suo valore viene inizializzato solo una volta prima dell'avvio del programma, come indicato nel riferimento cpp (l'inizializzazione non deve essere confusa con l'assegnazione)
diamo un'occhiata a un esempio.
//localVarDemo1.cpp
int localNextID()
{
int tempID = 1; //tempID created here
return tempID++; //copy of tempID returned and tempID incremented to 2
} //tempID destroyed here, hence value of tempID lost
int newNextID()
{
static int newID = 0;//newID has static duration, with internal linkage
return newID++; //copy of newID returned and newID incremented by 1
} //newID doesn't get destroyed here :-)
int main()
{
int employeeID1 = localNextID(); //employeeID1 = 1
int employeeID2 = localNextID(); // employeeID2 = 1 again (not desired)
int employeeID3 = newNextID(); //employeeID3 = 0;
int employeeID4 = newNextID(); //employeeID4 = 1;
int employeeID5 = newNextID(); //employeeID5 = 2;
return 0;
}
Guardando il criterio sopra per variabili locali statiche e variabili globali statiche, si potrebbe essere tentati di chiedere, quale potrebbe essere la differenza tra loro. Mentre le variabili globali sono accessibili in qualsiasi punto all'interno del codice (a stesso così come unità di traduzione differenti a seconda del const -ness e extern -ness), una variabile statica definita all'interno di un blocco funzione non è direttamente accessibile. La variabile deve essere restituita dal valore della funzione o dal riferimento. Dimostriamolo con un esempio:
//localVarDemo2.cpp
//static storage duration with global scope
//note this variable can be accessed from outside the file
//in a different compilation unit by using `extern` specifier
//which might not be desirable for certain use case.
static int globalId = 0;
int newNextID()
{
static int newID = 0;//newID has static duration, with internal linkage
return newID++; //copy of newID returned and newID incremented by 1
} //newID doesn't get destroyed here
int main()
{
//since globalId is accessible we use it directly
const int globalEmployee1Id = globalId++; //globalEmployeeId1 = 0;
const int globalEmployee2Id = globalId++; //globalEmployeeId1 = 1;
//const int employeeID1 = newID++; //this will lead to compilation error since newID++ is not accessible direcly.
int employeeID2 = newNextID(); //employeeID3 = 0;
int employeeID2 = newNextID(); //employeeID3 = 1;
return 0;
}
Ulteriori spiegazioni sulla scelta della variabile statica globale e statica locale possono essere trovate su questo thread stackoverflow
(ii) parola chiave statica per variabili all'interno di un blocco locale senza nome.
Le variabili statiche all'interno di un blocco locale (non un blocco funzione) non sono accessibili al di fuori del blocco una volta che il blocco locale esce dall'ambito. Nessun avvertimento per questa regola.
//localVarDemo3.cpp
int main()
{
{
const static int static_local_scoped_variable {99};
}//static_local_scoped_variable goes out of scope
//the line below causes compilation error
//do_something is an arbitrary function
do_something(static_local_scoped_variable);
return 0;
}
C ++ 11 ha introdotto la parola chiave constexpr
che garantisce la valutazione di un'espressione in fase di compilazione e consente al compilatore di ottimizzare il codice. Ora se il valore di una variabile const statica all'interno di un ambito è noto al momento della compilazione, il codice è ottimizzato in modo simile a quello con constexpr
. Ecco un piccolo esempio
Consiglio anche ai lettori di cercare la differenza tra constexpr
e static const
per le variabili in questo thread di StackOverflow . questo conclude la mia spiegazione per la parola chiave statica applicata alle variabili.
B. Parola chiave "statica" utilizzata per le funzioni
in termini di funzioni, la parola chiave statica ha un significato semplice. Qui, si riferisce al collegamento della funzione
Normalmente tutte le funzioni dichiarate all'interno di un file cpp hanno un collegamento esterno per impostazione predefinita, vale a dire una funzione definita in un file può essere utilizzata in un altro file cpp mediante dichiarazione diretta.
l'uso di una parola chiave statica prima della dichiarazione della funzione limita il suo collegamento a interno , ovvero una funzione statica non può essere utilizzata all'interno di un file al di fuori della sua definizione.
C. Parola chiave Staitc utilizzata per le variabili membro e le funzioni delle classi
1. Parola chiave "statica" per le variabili membro delle classi
Comincio direttamente con un esempio qui
#include <iostream>
class DesignNumber
{
private:
static int m_designNum; //design number
int m_iteration; // number of iterations performed for the design
public:
DesignNumber() { } //default constructor
int getItrNum() //get the iteration number of design
{
m_iteration = m_designNum++;
return m_iteration;
}
static int m_anyNumber; //public static variable
};
int DesignNumber::m_designNum = 0; // starting with design id = 0
// note : no need of static keyword here
//causes compiler error if static keyword used
int DesignNumber::m_anyNumber = 99; /* initialization of inclass public
static member */
enter code here
int main()
{
DesignNumber firstDesign, secondDesign, thirdDesign;
std::cout << firstDesign.getItrNum() << "\n"; //prints 0
std::cout << secondDesign.getItrNum() << "\n"; //prints 1
std::cout << thirdDesign.getItrNum() << "\n"; //prints 2
std::cout << DesignNumber::m_anyNumber++ << "\n"; /* no object
associated with m_anyNumber */
std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 100
std::cout << DesignNumber::m_anyNumber++ << "\n"; //prints 101
return 0;
}
In questo esempio, la variabile statica m_designNum conserva il suo valore e questa singola variabile del membro privato (perché è statica) è condivisa in b / n tutte le variabili del tipo di oggetto DesignNumber
Analogamente ad altre variabili membro, le variabili membro statiche di una classe non sono associate ad alcun oggetto di classe, come dimostrato dalla stampa di anyNumber nella funzione principale
const vs variabili non costanti del membro statico nella classe
(i) variabili membro statiche
non costanti Nell'esempio precedente i membri statici (sia pubblici che privati) erano non costanti. La norma ISO vieta l'inizializzazione di membri statici non costanti nella classe. Quindi, come nell'esempio precedente, devono essere inizializzati dopo la definizione della classe, con l'avvertenza che la parola chiave statica deve essere omessa
(ii) variabili membro const-static della classe
questo è semplice e si accompagna alla convenzione di inizializzazione di altre variabili const const, cioè le variabili costanti di un membro const di una classe possono essere inizializzate al punto di dichiarazione e possono essere inizializzate alla fine della dichiarazione di classe con un avvertimento che la parola chiave const deve essere aggiunta al membro statico quando viene inizializzata dopo la definizione della classe.
Vorrei tuttavia raccomandare di inizializzare le variabili costanti dei membri statici nel punto di dichiarazione. Questo vale con la convenzione C ++ standard e rende il codice più pulito
per ulteriori esempi sulle variabili statiche dei membri in una classe, cercare il seguente collegamento da learncpp.com
http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
2. Parola chiave "statica" per la funzione membro delle classi
Proprio come le variabili membro delle classi possono essere statiche, così come le funzioni membro delle classi. Le normali funzioni membro delle classi sono sempre associate a un oggetto del tipo di classe. Al contrario, le funzioni membro statiche di una classe non sono associate a nessun oggetto della classe, cioè non hanno * questo puntatore.
In secondo luogo, poiché le funzioni membro statiche della classe non hanno * questo puntatore, possono essere chiamate usando il nome della classe e l'operatore di risoluzione dell'ambito nella funzione principale (ClassName :: functionName ();)
Le funzioni di membro terzo statico di una classe possono accedere solo alle variabili membro statico di una classe, poiché le variabili membro non statico di una classe devono appartenere a un oggetto classe.
per ulteriori esempi sulle funzioni dei membri statici in una classe, cercare il seguente collegamento da learncpp.com
http://www.learncpp.com/cpp-tutorial/812-static-member-functions/