1. Was ist static?

static ist ein sehr häufig verwendeter Modifizierer in C/C++. Er wird verwendet, um den Speichermodus und die Sichtbarkeit von Variablen zu steuern.

1.1 Einführung in static

Wir wissen, dass der Compiler für Variablen, die innerhalb einer Funktion definiert werden, Speicherplatz auf dem Stack reserviert, wenn das Programm ihre Definition erreicht. Der von der Funktion auf dem Stack reservierte Speicherplatz wird freigegeben, wenn die Funktion die Ausführung beendet. Dies wirft ein Problem auf: Wenn Sie den Wert dieser Variablen in der Funktion bis zum nächsten Aufruf erhalten möchten, wie kann das erreicht werden? Die einfachste Methode, die einem einfällt, ist, sie als globale Variable zu definieren, aber das Definieren einer globalen Variablen hat viele Nachteile. Der offensichtlichste Nachteil ist, dass sie den Zugriffsbereich der Variablen zerstört (wodurch die in dieser Funktion definierte Variable nicht mehr nur von dieser Funktion kontrolliert wird). Das Schlüsselwort static kann dieses Problem gut lösen.

Darüber hinaus kann in C++ ein Datenobjekt, wenn es der gesamten Klasse statt einem bestimmten Objekt dienen soll und gleichzeitig versucht wird, die Kapselung der Klasse nicht zu durchbrechen, das heißt, wenn das Member innerhalb der Klasse verborgen und von außen unsichtbar sein soll, als statische Daten definiert werden.

1.2 Speicherung statischer Daten

Globaler (statischer) Speicherbereich: Er wird in das DATA-Segment und das BSS-Segment unterteilt. Das DATA-Segment (globaler initialisierter Bereich) speichert initialisierte globale Variablen und statische Variablen; das BSS-Segment (globaler nicht initialisierter Bereich) speichert nicht initialisierte globale Variablen und statische Variablen. Sie werden automatisch freigegeben, wenn das Programm endet. Unter ihnen wird das BSS-Segment vor der Programmausführung automatisch vom System auf 0 gesetzt, daher sind nicht initialisierte globale Variablen und statische Variablen bereits vor der Programmausführung 0. Variablen, die im statischen Datenbereich gespeichert sind, schließen ihre Initialisierung ab, wenn das Programm zum ersten Mal zu laufen beginnt, und dies ist die einzige Initialisierung.

Interner Implementierungsmechanismus von static in C++: Statische Datenelemente müssen existieren, sobald das Programm mit der Ausführung beginnt. Da Funktionen während der Programmausführung aufgerufen werden, können statische Datenelemente nicht innerhalb einer Funktion Speicher zugewiesen bekommen und initialisiert werden.

Auf diese Weise gibt es drei mögliche Stellen für seine Speicherzuweisung: erstens die Header-Datei als externe Schnittstelle der Klasse, in der sich die Klassendeklaration befindet; zweitens die interne Implementierung der Klassendefinition, in der sich die Definitionen der Memberfunktionen der Klasse befinden; drittens die globale Datendeklaration und -definition vor der main()-Funktion der Anwendung.

Statische Datenelemente müssen tatsächlich Speicherplatz belegen, daher können sie nicht in der Klassendeklaration definiert werden (nur Datenelemente können deklariert werden). Die Klassendeklaration deklariert nur die "Größe und Spezifikationen" einer Klasse und führt keine tatsächliche Speicherzuweisung durch, daher ist es falsch, eine Definition in der Klassendeklaration zu schreiben. Sie können auch nicht außerhalb der Klassendeklaration in einer Header-Datei definiert werden, da dies zu wiederholten Definitionen von ihnen in mehreren Quelldateien führen würde, die die Klasse verwenden.

static wird eingeführt, um dem Compiler mitzuteilen, Variablen im statischen Speicherbereich des Programms statt auf dem Stack zu speichern. Statische Datenelemente werden in der Reihenfolge initialisiert, in der sie definiert sind. Beachten Sie, dass bei verschachtelten statischen Membern sichergestellt werden muss, dass die verschachtelten Member bereits initialisiert wurden. Die Reihenfolge der Zerstörung ist die Umkehrung der Reihenfolge der Initialisierung.

Vorteile:Es kann Speicher sparen, da es von allen Objekten gemeinsam genutzt wird. Daher werden statische Datenelemente bei mehreren Objekten an einer Stelle gespeichert und von allen Objekten gemeinsam genutzt. Der Wert eines statischen Datenelements ist für jedes Objekt derselbe, aber sein Wert kann aktualisiert werden. Solange der Wert des statischen Datenelements einmal aktualisiert wird, ist garantiert, dass alle Objekte auf denselben aktualisierten Wert zugreifen, was die Zeiteffizienz verbessern kann.


2. Die Rolle von static in C/C++

2.1 Allgemein

  • (1) Wenn static Variablen modifiziert, wird die durch static modifizierte statische lokale Variable nur einmal initialisiert, und sie verlängert die Lebensdauer der lokalen Variablen, die erst freigegeben wird, wenn das Programm die Ausführung beendet.
  • (2) Wenn static eine globale Variable modifiziert, kann auf diese globale Variable nur in der aktuellen Datei zugegriffen werden und nicht in anderen Dateien, auch nicht mit einer extern-Deklaration.
  • (3) Wenn static eine Funktion modifiziert, kann diese Funktion nur in der aktuellen Datei aufgerufen werden und nicht von anderen Dateien aufgerufen werden. Durch static modifizierte Variablen werden im statischen Variablenbereich des globalen Datenbereichs gespeichert, einschließlich globaler statischer Variablen und lokaler statischer Variablen, die alle Speicher im globalen Datenbereich belegen. Sie werden während der Initialisierung automatisch auf 0 initialisiert.
  • (4) Wenn Sie nicht möchten, dass es freigegeben wird, können Sie static verwenden, um es zu modifizieren. Zum Beispiel ein Array, das im Stack-Speicher in einer Funktion gespeichert ist. Wenn Sie nicht möchten, dass das Array freigegeben wird, wenn der Funktionsaufruf endet, können Sie static verwenden, um es zu modifizieren.
  • (5) Berücksichtigen Sie die Datensicherheit (wenn das Programm globale Variablen verwenden möchte, sollte es zuerst die Verwendung von static in Betracht ziehen).

2.2 Statische Variablen und gewöhnliche Variablen

Statische globale Variablen haben die folgenden Eigenschaften:

  • (1) Statische Variablen belegen alle Speicher im globalen Datenbereich, einschließlich der später erwähnten statischen lokalen Variablen;
  • (2) Nicht initialisierte statische globale Variablen werden vom Programm automatisch auf 0 initialisiert (der Wert von automatischen Variablen, die innerhalb eines Funktionskörpers deklariert werden, ist zufällig, sofern sie nicht explizit initialisiert werden, und automatische Variablen, die außerhalb des Funktionskörpers deklariert werden, werden ebenfalls auf 0 initialisiert);
  • (3) Statische globale Variablen sind in der gesamten Datei sichtbar, in der sie deklariert werden, und außerhalb der Datei unsichtbar.

Vorteile:Statische globale Variablen können nicht von anderen Dateien verwendet werden; andere Dateien können Variablen mit demselben Namen definieren, ohne dass ein Konflikt entsteht.

(1) Der Unterschied zwischen globalen Variablen und globalen statischen Variablen

  • 1) Globale Variablen sind globale Variablen, die nicht explizit mit static modifiziert wurden. Globale Variablen haben standardmäßig externe Bindung, und ihr Gültigkeitsbereich ist das gesamte Projekt. Eine in einer Datei definierte globale Variable kann in einer anderen Datei verwendet werden, indem man 'extern globaler Variablenname' deklariert.
  • 2) Globale statische Variablen sind globale Variablen, die explizit mit static modifiziert wurden. Ihr Gültigkeitsbereich ist die Datei, in der die Variable deklariert ist. Andere Dateien können sie nicht verwenden, selbst mit einer extern-Deklaration nicht.

2.3 Statische lokale Variablen haben die folgenden Eigenschaften:

  • (1) Diese Variable belegt Speicher im globalen Datenbereich;
  • (2) Eine statische lokale Variable wird zum ersten Mal initialisiert, wenn das Programm die Deklaration des Objekts ausführt, d. h. nachfolgende Funktionsaufrufe initialisieren sie nicht erneut;
  • (3) Statische lokale Variablen werden im Allgemeinen bei der Deklaration initialisiert. Wenn es keine explizite Initialisierung gibt, werden sie vom Programm automatisch auf 0 initialisiert;
  • (4) Sie verbleibt immer im globalen Datenbereich, bis das Programm die Ausführung beendet. Aber ihr Gültigkeitsbereich ist ein lokaler Gültigkeitsbereich. Wenn die Funktion oder der Anweisungsblock, der sie definiert, endet, endet auch ihr Gültigkeitsbereich.

Im Allgemeinen speichern Programme neu erzeugte dynamische Daten im Heap-Bereich und automatische Variablen innerhalb von Funktionen im Stack-Bereich. Automatische Variablen geben im Allgemeinen Speicher frei, wenn die Funktion beendet wird. Statische Daten (sogar statische lokale Variablen innerhalb von Funktionen) werden ebenfalls im globalen Datenbereich gespeichert. Daten im globalen Datenbereich werden nicht wegen des Beendens einer Funktion freigegeben.

Betrachten Sie das folgende Beispiel:

Beispiel

//Beispiel: #include <stdio.h> #include <stdlib.h> int k1 = 1; int k2; static int k3 = 2; static int k4; int main() { static int m1 = 2, m2; int i = 1; char*p; char str[10] = "hello"; char*q = "hello"; p = (char *)malloc(100); free(p); printf("Stack-Bereich - Variablenadresse i: %p\n", &i); printf("Stack-Bereich - Variablenadresse p: %p\n", &p); printf("Stack-Bereich - Variablenadresse str: %p\n", str); printf("Stack-Bereich - Variablenadresse q: %p\n", &q); printf("Heap-Bereichsadresse - dynamische Speicherzuweisung: %p\n", p); printf("Global extern mit Anfangswert k1: %p\n", &k1); printf("Extern ohne Anfangswert k2: %p\n", &k2); printf("Statisch extern mit Initialwert k3: %p\n", &k3); printf("Extern statisch ohne Initialwert k4: %p\n", &k4); printf("Intern statisch mit Initialwert m1: %p\n", &m1); printf("Intern statisch ohne Initialwert m2: %p\n", &m2); printf("Adresse des String-Literals: %p, %s\n", q, q); printf("Adresse des Programmbereichs: %p\n", &main); return 0; }

Das Ausgabeergebnis ist wie folgt:


3. Verwendung von static

3.1 In C++

Die grundlegendste Verwendung des Schlüsselworts static ist:

  • 1. Durch static modifizierte Variablen gehören zu Klassenvariablen und können direkt durchKlassenname.Variablennamedirekt referenziert werden, ohne eine Klasse mit new erzeugen zu müssen.
  • 2. Durch static modifizierte Methoden gehören zu Klassenmethoden und können direkt durchKlassenname.Methodennamedirekt referenziert werden, ohne eine Klasse mit new erzeugen zu müssen.

Durch static modifizierte Variablen und durch static modifizierte Methoden gehören gemeinsam zu den statischen Ressourcen der Klasse und werden unter Klasseninstanzen geteilt. Mit anderen Worten: Wenn es sich an einer Stelle ändert, ändert es sich überall.

In C++ gehören statische Member zur gesamten Klasse und nicht zu einem bestimmten Objekt. Statische Membervariablen werden nur einmal für alle Objekte gespeichert, damit sie gemeinsam genutzt werden können. Daher können sie von allen Objekten gemeinsam verwendet werden. Die Verwendung statischer Membervariablen zur gemeinsamen Datennutzung durch mehrere Objekte durchbricht nicht das Verbergungsprinzip, gewährleistet Sicherheit und spart Speicher.

Die Definition oder Deklaration statischer Member muss das Schlüsselwort static enthalten. Statische Member können über den Doppeldoppelpunkt verwendet werden, d. h.<Klassenname>::<Name des statischen Members>。

3.2 Im Zusammenhang mit statischen Klassen

Aufruf statischer Memberfunktionen und nicht-statischer Memberfunktionen über den Klassennamen:
class Point { public: void init() { } static void output() { } }; void main() { Point::init(); Point::output(); }

Fehler:

'Point::init' : illegal call of non-static member function

Schlussfolgerung 1:Die nicht-statischen Memberfunktionen einer Klasse können nicht über den Klassennamen aufgerufen werden.

Aufruf statischer Memberfunktionen und nicht-statischer Memberfunktionen über ein Objekt der Klasse.

class Point { public: void init() { } static void output() { } }; void main() { Point pt; pt.init(); pt.output(); }

Kompilierungsdurchläufe.

Schlussfolgerung 2: Objekte der Klasse können statische Memberfunktionen und nichtstatische Memberfunktionen verwenden.

Verwendung nichtstatischer Member der Klasse in einer statischen Memberfunktion der Klasse.

#include <stdio.h> class Point { public: void init() { } static void output() { printf("%d\n", m_x); } private: int m_x; }; void main() { Point pt; pt.output(); }

Kompilierungsfehler:

error C2597: illegal reference to data member 'Point::m_x' in a static member function

Weil eine statische Memberfunktion zur gesamten Klasse gehört und Speicher für sie reserviert wird, bevor die Klasse ein Objekt instanziiert, während ein nichtstatisches Member der Klasse erst dann Speicherplatz haben kann, nachdem ein Objekt instanziiert wurde, schlägt dieser Aufruf fehl. Es ist, als würde man eine Variable verwenden, bevor sie deklariert wurde.

Schlussfolgerung 3:Nichtstatische Member können in statischen Memberfunktionen nicht referenziert werden.

Verwendung statischer Member der Klasse in nichtstatischen Memberfunktionen der Klasse.

class Point { public: void init() { output(); } static void output() { } }; void main() { Point pt; Pt.init(); pt.output(); }

Kompilierungsdurchläufe.

Schlussfolgerung 4: Nicht-statische Memberfunktionen einer Klasse können statische Memberfunktionen aufrufen, aber das Umgekehrte ist nicht möglich.

Verwendung statischer Membervariablen der Klasse.

#include <stdio.h> class Point { public: Point() { m_nPointCount++; } ~Point() { m_nPointCount--; } static void output() { printf("%d\n", m_nPointCount); } private: static int m_nPointCount; }; void main() { Point pt; pt.output(); }

Drücken SieCtrl+F7Die Kompilierung ist fehlerfrei, aber beim Drücken von F7 zum Generieren des EXE-Programms wird ein Linkerfehler gemeldet.

error LNK2001: unresolved external symbol "private: static int Point::m_nPointCount" (?m_nPointCount@Point@@0HA)

Das liegt daran, dass statische Membervariablen der Klasse vor der Verwendung initialisiert werden müssen.

Inmain()Vor der Funktion hinzufügenint Point::m_nPointCount = 0;Erneut fehlerfrei kompilieren und linken, und beim Ausführen des Programms wird 1 ausgegeben.

Schlussfolgerung 5: Statische Membervariablen einer Klasse müssen vor der Verwendung initialisiert werden.

Zusammenfassung der Reflexion:Statische Ressourcen gehören zur Klasse, existieren aber unabhängig von der Klasse. Aus Sicht des Lademechanismus der Klasse J werden statische Ressourcen geladen, wenn die Klasse initialisiert wird, wohingegen nichtstatische Ressourcen geladen werden, wenn die Klasse ein Objekt instanziiert. Die Klasseninitialisierung erfolgt früher als die Klasseninstanziierung; zum Beispiel,Class.forName("xxx")eine Methode initialisiert eine Klasse, instanziiert aber kein Objekt; sie lädt nur die statischen Ressourcen der Klasse. Daher ist es für statische Ressourcen unmöglich zu wissen, welche nichtstatischen Ressourcen in einer Klasse existieren. Bei nichtstatischen Ressourcen ist es jedoch anders: Da sie entstehen, nachdem ein Objekt instanziiert wurde, können sie all diese Dinge erkennen, die zur Klasse gehören. Die Antworten auf die obigen Fragen sind also sehr klar:

  • 1) Können statische Methoden auf nichtstatische Ressourcen verweisen? Nein. Dinge, die erst entstehen, wenn ein Objekt instanziiert wird, werden von statischen Ressourcen, die nach der Initialisierung bereits existieren, einfach nicht erkannt.
  • 2) Können statische Ressourcen innerhalb statischer Methoden referenziert werden? Ja, denn sie werden alle während der Klasseninitialisierung geladen, und sie kennen sich alle gegenseitig.
  • 3) Können statische Ressourcen innerhalb nichtstatischer Methoden referenziert werden? Ja. Nichtstatische Methoden sind Instanzmethoden, die erst nach dem Instanziieren eines Objekts entstehen, daher erkennen sie alle Inhalte, die zur Klasse gehören.

(static als Modifizierer einer Klasse:Diese Verwendung ist viel seltener als die vorherigen. Im Allgemeinen kann static eine Klasse nicht modifizieren. Wenn static eine Klasse modifiziert, bedeutet das, dass die Klasse eine statische innere Klasse ist (beachten Sie, dass static nur eine innere Klasse modifizieren kann), also eine anonyme innere Klasse. Zum Beispiel sind die vier Ablehnungsmechanismen im Thread-Pool ThreadPoolExecutor – CallerRunsPolicy, AbortPolicy, DiscardPolicy, DiscardOldestPolicy – statische innere Klassen. Inhalte zu statischen inneren Klassen werden speziell beim Schreiben über innere Klassen behandelt.)

3.3 Zusammenfassung:

  • (1) Nicht-statische Member können nicht in statischen Memberfunktionen aufgerufen werden.
  • (2) Statische Member können in nicht-statischen Memberfunktionen aufgerufen werden. Da statische Member zur Klasse selbst gehören und bereits existieren, bevor ein Objekt der Klasse erzeugt wird, können statische Member in nicht-statischen Memberfunktionen aufgerufen werden.
  • (3) Statische Membervariablen müssen vor der Verwendung initialisiert werden (z. B.int MyClass::m_nNumber = 0;), andernfalls tritt zur Linkzeit ein Fehler auf.

Allgemeine Zusammenfassung: In einer Klasse kann static verwendet werden, um statische Datenelemente und statische Membermethoden zu modifizieren.

Statische Datenelemente

  • (1) Statische Datenelemente können die gemeinsame Nutzung von Daten zwischen mehreren Objekten realisieren. Sie sind gemeinsame Member aller Objekte der Klasse und belegen nur einen Speicherplatz. Wenn sich ihr Wert ändert, ändert sich auch der Wert dieses Datenelements in jedem Objekt.
  • (2) Statischen Datenelementen wird Speicher zugewiesen, wenn das Programm zu laufen beginnt, und dieser wird erst freigegeben, wenn das Programm endet. Sobald ein statisches Datenelement in der Klasse angegeben ist, wird dafür Speicher zugewiesen, selbst wenn kein Objekt definiert ist.
  • (3) Statische Datenelemente können initialisiert werden, aber nur außerhalb des Klassenkörpers. Wenn einem statischen Datenelement kein Anfangswert zugewiesen wird, initialisiert der Compiler es automatisch mit 0.
  • (4) Statische Datenelemente können sowohl über den Objektnamen als auch über den Klassennamen referenziert werden.

Statische Memberfunktionen

  • (1) Wie statische Datenelemente gehören statische Memberfunktionen zu den statischen Mitgliedern der Klasse, nicht zu den Objektmitgliedern.
  • (2) Nicht-statische Memberfunktionen besitzen einen this-Zeiger, während statische Memberfunktionen keinen this-Zeiger besitzen.
  • (3) Statische Memberfunktionen werden hauptsächlich verwendet, um auf statische Datenelemente zuzugreifen, und können nicht auf nicht-statische Member zugreifen.

Lassen Sie uns ein weiteres Beispiel mit statischen Membervariablen und -funktionen einer Klasse geben, um das Verständnis zu vertiefen. Dieses Beispiel erstellt eine Studentenklasse. Objekte jeder Studentenklasse bilden eine doppelt verkettete Liste. Eine statische Membervariable speichert den Kopf der doppelt verketteten Liste, und eine statische Memberfunktion gibt diese doppelt verkettete Liste aus.

Beispiel

#include <stdio.h> #include <string.h> const int MAX_NAME_SIZE = 30; class Student { public: Student(char *pszName); ~Student(); public: static void PrintfAllStudents(); private: char m_name[MAX_NAME_SIZE]; Student *next; Student *prev; static Student *m_head; }; Student::Student(char *pszName) { strcpy(this->m_name, pszName); //Eine doppelt verkettete Liste aufbauen, neue Daten werden vom Kopf der Liste eingefügt. this->next = m_head; this->prev = NULL; if (m_head != NULL) m_head->prev = this; m_head = this; } Student::~Student ()//Der Zerstörungsprozess ist der Ablösungsprozess der Knoten { if (this == m_head) //Dieser Knoten ist der Kopfknoten. { m_head = this->next; } else { this->prev->next = this->next; this->next->prev = this->prev; } } void Student::PrintfAllStudents() { for (Student *p = m_head; p != NULL; p = p->next) printf("%s\n", p->m_name); } Student* Student::m_head = NULL; void main() { Student studentA("AAA"); Student studentB("BBB"); Student studentC("CCC"); Student studentD("DDD"); Student student("MoreWindows"); Student::PrintfAllStudents(); }

Das Programm wird ausgeben:

Originaladresse: https://www.cnblogs.com/33debug/p/7223869.html