Um die Frage zu klären, würde ich die Verwendung des Schlüsselworts "statisch" lieber in drei verschiedene Formen einteilen:
(EIN). Variablen
(B). Funktionen
(C). Mitgliedsvariablen / Funktionen von Klassen
Die folgende Erklärung folgt für jede der Unterüberschriften:
(A) 'statisches' Schlüsselwort für Variablen
Dieser kann etwas knifflig sein, aber wenn er richtig erklärt und verstanden wird, ist er ziemlich einfach.
Um dies zu erklären, ist es zunächst sehr nützlich, den Umfang, die Dauer und die Verknüpfung von Variablen zu kennen, ohne die das trübe Konzept des staischen Schlüsselworts immer nur schwer zu erkennen ist
1. Bereich : Legt fest, wo in der Datei auf die Variable zugegriffen werden kann. Es kann zwei Arten geben: (i) Lokaler oder Blockbereich . (ii) Globaler Geltungsbereich
2. Dauer : Legt fest, wann eine Variable erstellt und zerstört wird. Es gibt wieder zwei Arten: (i) Automatische Speicherdauer (für Variablen mit lokalem oder Blockbereich). (ii) Statische Speicherdauer (für Variablen mit globalem Gültigkeitsbereich oder lokale Variablen (in einer Funktion oder einem Codeblock) mit statischem Bezeichner).
3. Verknüpfung : Legt fest, ob auf eine Variable in einer anderen Datei zugegriffen (oder verknüpft) werden kann. Wieder (und zum Glück) gibt es zwei Arten: (i) Interne Verknüpfung
(für Variablen mit Blockbereich und globalem Bereich / Dateibereich / globaler Namespace-Bereich) (ii) Externe Verknüpfung (für Variablen mit nur globalem Bereich / Dateibereich / Globaler Namespace-Bereich)
Im Folgenden finden Sie ein Beispiel zum besseren Verständnis einfacher globaler und lokaler Variablen (keine lokalen Variablen mit statischer Speicherdauer):
//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
Jetzt kommt das Konzept der Verknüpfung. Wenn eine in einer Datei definierte globale Variable in einer anderen Datei verwendet werden soll, spielt die Verknüpfung der Variablen eine wichtige Rolle.
Die Verknüpfung globaler Variablen wird durch die Schlüsselwörter (i) statisch und (ii) extern angegeben
(Jetzt bekommst du die Erklärung)
Das statische Schlüsselwort kann auf Variablen mit lokalem und globalem Gültigkeitsbereich angewendet werden. In beiden Fällen bedeuten sie unterschiedliche Bedeutungen. Ich werde zuerst die Verwendung des Schlüsselworts 'static' in Variablen mit globalem Gültigkeitsbereich erläutern (wobei ich auch die Verwendung des Schlüsselworts 'extern' erläutere) und später die Verwendung für Schlüsselwörter mit lokalem Gültigkeitsbereich.
1. Statisches Schlüsselwort für Variablen mit globalem Gültigkeitsbereich
Globale Variablen haben eine statische Dauer, dh sie verlassen nicht den Gültigkeitsbereich, wenn ein bestimmter Codeblock (z. B. main ()), in dem er verwendet wird, endet. Abhängig von der Verknüpfung kann auf sie entweder nur innerhalb derselben Datei zugegriffen werden, in der sie deklariert sind (für statische globale Variablen), oder außerhalb der Datei, sogar außerhalb der Datei, in der sie deklariert sind (globale Variablen vom externen Typ).
Im Fall einer globalen Variablen mit externem Bezeichner und wenn auf diese Variable außerhalb der Datei zugegriffen wird, in der sie initialisiert wurde, muss sie in der Datei, in der sie verwendet wird, vorwärts deklariert werden, genau wie eine Funktion weitergeleitet werden muss deklariert, wenn sich die Definition in einer anderen Datei befindet als der, in dem sie verwendet wird.
Wenn die globale Variable dagegen ein statisches Schlüsselwort hat, kann sie nicht in einer Datei verwendet werden, außerhalb derer sie deklariert wurde.
(Zur Verdeutlichung siehe Beispiel unten)
z.B:
//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;
}
Jetzt kann jede Variable in c ++ entweder eine Konstante oder eine Nicht-Konstante sein, und für jede 'Konstanz' erhalten wir zwei Fälle von Standard-C ++ - Verknüpfung, falls keine angegeben ist:
(i) Wenn eine globale Variable nicht const ist, ist ihre Verknüpfung standardmäßig extern , dh auf die globale Variable nicht const kann in einer anderen CPP-Datei durch Vorwärtsdeklaration unter Verwendung des Schlüsselworts extern (mit anderen Worten non const global) zugegriffen werden Variablen haben eine externe Verknüpfung (natürlich mit statischer Dauer). Auch die Verwendung des externen Schlüsselworts in der Originaldatei, in der es definiert wurde, ist redundant. Verwenden Sie in diesem Fall den Bezeichner 'static' vor dem Variablentyp, um eine nicht konstante globale Variable für externe Dateien unzugänglich zu machen .
(ii) Wenn eine globale Variable const ist, ist ihre Verknüpfung standardmäßig statisch , dh auf eine globale const-Variable kann in einer anderen Datei als der definierten nicht zugegriffen werden (mit anderen Worten, globale const-Variablen haben eine interne Verknüpfung (mit statischer Dauer) natürlich)). Auch die Verwendung eines statischen Schlüsselworts, um zu verhindern, dass auf eine globale Variable const in einer anderen Datei zugegriffen wird, ist redundant. Verwenden Sie hier den Bezeichner 'extern' vor dem Typ der Variablen , um eine konstante globale Variable mit einer externen Verknüpfung zu versehen
Hier ist eine Zusammenfassung für globale Bereichsvariablen mit verschiedenen Verknüpfungen
//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
Als nächstes untersuchen wir, wie sich die oben genannten globalen Variablen verhalten, wenn auf sie in einer anderen Datei zugegriffen wird.
//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. Statisches Schlüsselwort für Variablen mit lokalem Bereich
Aktualisierungen (August 2019) des statischen Schlüsselworts für Variablen im lokalen Bereich
Dies kann weiter in zwei Kategorien unterteilt werden:
(i) statisches Schlüsselwort für Variablen innerhalb eines Funktionsblocks und (ii) statisches Schlüsselwort für Variablen innerhalb eines unbenannten lokalen Blocks.
(i) statisches Schlüsselwort für Variablen innerhalb eines Funktionsblocks.
Ich habe bereits erwähnt, dass Variablen mit lokalem Gültigkeitsbereich eine automatische Dauer haben, dh sie entstehen, wenn der Block eingegeben wird (sei es ein normaler Block, sei es ein Funktionsblock), und hören auf zu existieren, wenn der Block endet, kurz gesagt, Variablen mit lokalem Gültigkeitsbereich haben automatische Dauer und automatische Dauervariablen (und Objekte) haben keine Verknüpfung, was bedeutet, dass sie außerhalb des Codeblocks nicht sichtbar sind.
Wenn ein statischer Bezeichner auf eine lokale Variable innerhalb eines Funktionsblocks angewendet wird, ändert er die Dauer der Variablen von automatisch in statisch und ihre Lebensdauer entspricht der gesamten Dauer des Programms. Dies bedeutet, dass sie einen festen Speicherort hat und ihr Wert nur initialisiert wird einmal vor dem Programmstart wie in der CPP-Referenz angegeben (Initialisierung sollte nicht mit Zuweisung verwechselt werden)
Schauen wir uns ein Beispiel an.
//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;
}
Wenn man das obige Kriterium für statische lokale Variablen und statische globale Variablen betrachtet, könnte man versucht sein zu fragen, was der Unterschied zwischen ihnen sein könnte. Während die globalen Variablen an jedem Punkt in dem Code innerhalb zugänglich sind (in gleichen als auch unterschiedlichen Übersetzungseinheit in Abhängigkeit von der const -ness und extern -ness), ist eine statische Variable innerhalb eines Funktionsblocks definiert , die nicht direkt zugänglich sind . Die Variable muss durch den Funktionswert oder die Referenz zurückgegeben werden. Lassen Sie uns dies anhand eines Beispiels demonstrieren:
//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;
}
Weitere Erläuterungen zur Auswahl der statischen globalen und statischen lokalen Variablen finden Sie in diesem Stackoverflow-Thread
(ii) statisches Schlüsselwort für Variablen innerhalb eines unbenannten lokalen Blocks.
Auf statische Variablen innerhalb eines lokalen Blocks (kein Funktionsblock) kann außerhalb des Blocks nicht zugegriffen werden, sobald der lokale Block den Gültigkeitsbereich verlässt. Keine Einschränkungen dieser Regel.
//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;
}
In C ++ 11 wurde das Schlüsselwort eingeführt, constexpr
das die Auswertung eines Ausdrucks zur Kompilierungszeit garantiert und es dem Compiler ermöglicht, den Code zu optimieren. Wenn nun der Wert einer statischen const-Variablen innerhalb eines Bereichs zur Kompilierungszeit bekannt ist, wird der Code auf ähnliche Weise wie bei optimiert constexpr
. Hier ist ein kleines Beispiel
Ich empfehle den Lesern auch, den Unterschied zwischen constexpr
und static const
für Variablen in diesem Stackoverflow-Thread nachzuschlagen . Damit ist meine Erklärung für das statische Schlüsselwort abgeschlossen, das auf Variablen angewendet wird.
B. 'statisches' Schlüsselwort für Funktionen
In Bezug auf Funktionen hat das statische Schlüsselwort eine einfache Bedeutung. Hier bezieht es sich auf die Verknüpfung der Funktion
Normalerweise haben alle in einer CPP-Datei deklarierten Funktionen standardmäßig eine externe Verknüpfung, dh eine in einer Datei definierte Funktion kann in einer anderen CPP-Datei durch Vorwärtsdeklaration verwendet werden.
Die Verwendung eines statischen Schlüsselworts vor der Funktionsdeklaration beschränkt die Verknüpfung mit intern , dh eine statische Funktion kann nicht innerhalb einer Datei außerhalb ihrer Definition verwendet werden.
C. Staitc-Schlüsselwort, das für Elementvariablen und Funktionen von Klassen verwendet wird
1. Schlüsselwort 'static' für Mitgliedsvariablen von Klassen
Ich beginne hier direkt mit einem Beispiel
#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 diesem Beispiel behält die statische Variable m_designNum ihren Wert bei, und diese einzelne private Mitgliedsvariable (da sie statisch ist) wird s / w mit allen Variablen des Objekttyps DesignNumber geteilt
Ebenso wie andere Elementvariablen sind statische Elementvariablen einer Klasse keinem Klassenobjekt zugeordnet, was durch das Drucken von anyNumber in der Hauptfunktion demonstriert wird
const vs nicht-const statische Elementvariablen in der Klasse
(i) statische Elementvariablen der Klasse "
Nicht-Konstante" Im vorherigen Beispiel waren die statischen Elemente (sowohl öffentliche als auch private) Nichtkonstanten. Der ISO-Standard verbietet die Initialisierung von nicht konstanten statischen Elementen in der Klasse. Daher müssen sie wie im vorherigen Beispiel nach der Klassendefinition initialisiert werden, mit der Einschränkung, dass das statische Schlüsselwort weggelassen werden muss
(ii) const-statische Elementvariablen der Klasse
Dies ist unkompliziert und entspricht der Konvention der Initialisierung anderer const-Elementvariablen, dh die konstanten statischen Elementvariablen einer Klasse können zum Zeitpunkt der Deklaration initialisiert und am Ende initialisiert werden der Klassendeklaration mit einer Einschränkung, dass das Schlüsselwort const dem statischen Element hinzugefügt werden muss, wenn es nach der Klassendefinition initialisiert wird.
Ich würde jedoch empfehlen, die statischen Elementvariablen const am Deklarationspunkt zu initialisieren. Dies entspricht der Standard-C ++ - Konvention und lässt den Code sauberer aussehen
Weitere Beispiele für statische Elementvariablen in einer Klasse finden Sie unter folgendem Link unter learncpp.com
http://www.learncpp.com/cpp-tutorial/811-static-member-variables/
2. Schlüsselwort 'static' für die Mitgliedsfunktion von Klassen
Genau wie Mitgliedsvariablen von Klassen statisch sein können, können auch Mitgliedsfunktionen von Klassen statisch sein. Normale Elementfunktionen von Klassen sind immer einem Objekt des Klassentyps zugeordnet. Im Gegensatz dazu sind statische Elementfunktionen einer Klasse keinem Objekt der Klasse zugeordnet, dh sie haben keinen * diesen Zeiger.
Zweitens, da die statischen Elementfunktionen der Klasse keinen * diesen Zeiger haben, können sie mit dem Operator Klassenname und Bereichsauflösung in der Hauptfunktion (ClassName :: functionName ();) aufgerufen werden.
Drittens können statische Elementfunktionen einer Klasse nur auf statische Elementvariablen einer Klasse zugreifen, da nicht statische Elementvariablen einer Klasse zu einem Klassenobjekt gehören müssen.
Weitere Beispiele für statische Elementfunktionen in einer Klasse finden Sie unter folgendem Link von learncpp.com
http://www.learncpp.com/cpp-tutorial/812-static-member-functions/