Klassenvariable, Instanzvariable, Lokale Variable....



  • Guten Tag,
    ich habe jetzt schon sehr lange im Internet gesucht und auch ein Buch zur Hilfe genommen (Der C++ Programmierer), aber ich finde keine Antwort.

    Es geht um die ganzen Begrifflichkeiten: Klassen-, Instanz-, Lokale-, Globale- und Objektvariable. Haben alle unterschiedliche Bedeutungen oder gibt es mehrere Namen für das gleiche?

    Für mich ist eine Globale Variable, dasselbe wie eine Objektvariable und eine Instanzvariable oder sehe ich das falsch?

    Meine Ergebnisse bisher:

    Globale Variablen:
    -werden außerhalb einer Funktion deklariert und gelten in allen Funktionen

    Lokale Variablen:
    -werden innerhalb einer Funktion deklariert und gelten nur innerhalb einer Funktion

    Klassenvariablen:
    -sind innerhalb einer ganzen Klasse sichtbar und wird mit dem Schlüsselwort static deklariert
    -ist für jedes Objekt der Klasse verfügbar und hat unabhängig vom jeweiligen Objekt immer den selben Wert

    Instanzvariablen:
    -kann in einem Objekt individuelle Werte annehmen und werden innerhalb eines Klassenblockes deklariert

    Und der Unterschied zwischen Klassen- und Objektmethoden ist einfach, dass Klassenmethoden mit dem Schlüsselwort static deklariert werden und Objektmethoden nicht, oder?

    Ich bitte um eine Ergänzung, sollte ich da irgendwelche Dummheiten stehen haben.


  • Gesperrt

    @KogoroMori21 sagte in Klassenvariable, Instanzvariable, Lokale Variable....:

    Für mich ist eine Globale Variable, dasselbe wie eine Objektvariable und eine Instanzvariable oder sehe ich das falsch?

    Es kommt auf den Kontext an, in dem du dich bewegst, ob objektorienteiert, imperativ, prozedural oder funktional...

    Im OO-Kontext sind "globale Variablen" entweder Objekt- (manchmal auch Instanz- genannt) oder Klassenvariablen, ja.



  • @KogoroMori21 sagte in Klassenvariable, Instanzvariable, Lokale Variable....:

    Und der Unterschied zwischen Klassen- und Objektmethoden ist einfach, dass Klassenmethoden mit dem Schlüsselwort static deklariert werden und Objektmethoden nicht, oder?

    Naja, nicht der einzige Unterschied.

    In Klassenmethoden hast du keinen Zugriff auf Instanzvariablen (=Objektvariablen) oder Objektmethoden.
    Und Klassenmethoden können ohne Objekt aufgerufen werden (mit MeineKlasse::MeineMethode()).

    Objektmethoden haben diese Eigenschaften nicht.



  • Globale Variablen:
    -werden außerhalb einer Funktion deklariert und gelten in allen Funktionen
    

    Ich möchte Dir Deinen "Brei" nicht voreilig verderben, aber da gibt es noch so Haarspaltereien leider.

    "Übersetzungseinheiten" ("translation units")

    Ein sehr blödes Wort, ich weiß.
    Was ist denn das?
    Grob gesagt eine .h-Datei und eine .cpp-Datei (bzw. eine .c-Datei, wenn Du bei C bist).

    Aber das war wohl zu grob definiert.
    Machen wir es feiner.

    Präprozessor hast Du ja schonmal sicher gehört, oder?
    Das ist das Ding, dass Deine #incldue <iostream> und #define MEINE_SCHOENE_ZAHL 42 textuell verarbeitet und dann in Deinem Code ersetzt.

    Und dann haben wir ja Herr C++-Kompilierer (der Verlinker/Verbinder ist mit einbegriffen).
    Was nimmt er denn als Eingabe?
    Nun ja, er nimmt Deine Quellcodedateien (Übersetzungseinheiten), also Deine .cpp-Dateien als Eingabe.

    Also eigentlich ist die .cpp-Datei Deine Übersetzungseinheit, nachdem der Präprozessor fertig gearbeitet hat und "Feierabend" macht.
    (Wohl möglich noch in eine Kneipe geht und aus einer Existenzkrise heraus, sich besauft.
    "Werde ich etwa nicht mehr gebraucht? Werden Module in kommenden C++XX-Standards mich verdrängen?"
    )

    Wenn Du jetzt sagst, dass

    // MeineDatei.cpp
    
    int bin_ich_wirklich_von_ueberall_aus_zu_sehen;
    
    void ja_ich_sehe_dich(void) {
      int x = bin_ich_wirklich_von_ueberall_aus_zu_sehen;
      // ...
    }
    

    auch in

    // MeineAndereDatei.cpp
    
    void ich_sehe_dich_nicht(void) {
      int x = bin_ich_wirklich_von_ueberall_aus_zu_sehen; // FEHLER!!!
      // ...
    }
    

    Zu sehen ist, dann stimmt das nicht.

    Was Du machen kannst, ist

    // MeineAndereDatei.cpp
    
    void ich_sehe_dich_nicht(void) {
      extern int bin_ich_wirklich_von_ueberall_aus_zu_sehen;
      int x = bin_ich_wirklich_von_ueberall_aus_zu_sehen;
      // ...
    }
    

    Mit extern signalisierst Du dem Kompilierer (bzw. dem Linker), dass Du die globale Variable in einer anderen .cpp-Datei (Übersetzungseinheit) deklariert hast.

    Wenn Du jetzt aber static machst, also

    // MeineDatei.cpp
    
    static int bin_ich_wirklich_von_ueberall_aus_zu_sehen;
    
    void ja_man_ich_sehe_dich(void) {
      int x = bin_ich_wirklich_von_ueberall_aus_zu_sehen;
      // ...
    }
    

    Dann ist diese globale Variable auch nur wirklich MeineDatei.cpp zu sehen.
    Nirgendwo anders.

    ... sagst Du dem Kompilierer, dass das nur in der Übersetzungseinheit MeineDatei.cpp zugreifbar bleibt.
    (Bei MeineAndereDatei.cpp kannst Du dann diese globale Variable nicht mehr verwenden.)

    Man spricht im Zusammenhang mit globalen Variablen (Bezeichnern) bei extern von externer Anbindung ("external linkage").
    Bei static hingen von interner Anbindung "internal linkage".
    Die ganzen Anbindungen macht dabei der Verbinder/Linker.
    Der Verbinder/Linker muss wissen, wo ein Bezeichner (diese globale Variable zum Beispiel) zugreifbar ist und wo halt nicht.

    Das kannst Du, wenn Du mal Lust hast, auch im C++-Sprachstandard nachlesen.

    Da gibt es noch mehr Stolperfallen und Fallstricke.

    Wenn Du meinst, Du kannst das hier machen

    // MeineDatei.cpp
    
    int bin_ich_wirklich_von_ueberall_aus_zu_sehen;
    
    void ja_ich_sehe_dich(void) {
      int x = bin_ich_wirklich_von_ueberall_aus_zu_sehen;
      // ...
    }
    

    auch in

    // MeineAndereDatei.cpp
    
    int bin_ich_wirklich_von_ueberall_aus_zu_sehen; // FEHLER!!!
    
    void ich_sehe_dich_nicht(void) {
      int x = bin_ich_wirklich_von_ueberall_aus_zu_sehen; // FEHLER!!!
      // ...
    }
    

    Dann muss ich Dich leider wieder enttäuschen.
    Der Verbinder/Linker sieht bin_ich_wirklich_von_ueberall_aus_zu_sehen 2 mal.
    Du darfst aber Bezeichner (also Variablen- und Funktionsnamen) nur einmal innerhalb eines Gültigkeitsbereichs (zum Beispiel bei globalen Sachen innerhalb einer .cpp-Datei haben bzw. innerhalb von { und } bei lokalen Sachen.)

    Du kannst aber dann das hier machen:

    // MeineDatei.cpp
    
    static int bin_ich_wirklich_von_ueberall_aus_zu_sehen;
    
    void ja_ich_sehe_dich(void) {
      int x = bin_ich_wirklich_von_ueberall_aus_zu_sehen;
      // ...
    }
    

    auch in

    // MeineAndereDatei.cpp
    
    static int bin_ich_wirklich_von_ueberall_aus_zu_sehen;
    
    void ich_sehe_dich_nicht(void) {
      int x = bin_ich_wirklich_von_ueberall_aus_zu_sehen;
      // ...
    }
    

    Dann sagt der Verbinder/Linker "ah ja, der meint, ich soll die separat behandeln".
    Also wie im Restaurant, wo am Ende alle sagen "ich zahle getrennt".

    Kleine Denkaufgabe, wenn Du magst.
    Was meinst Du, was passiert, wenn Du

    static int bin_ich_wirklich_von_ueberall_aus_zu_sehen;

    ... in einer .h bzw. .hpp-Datei hast?
    Präprozessoren ersetzen Deine #include-Anweisung mit dem Inhalt Deiner .h bzw. .hpp-Datei.
    Was haben wir bei doppelten Definitionen gesagt?

    Also

    static und extern je nach Kontext haben eine andere Bedeutung.
    In Klassen heißt das, ja also eine statische Variable wird von vielen dieser "Instanzen" geteilt.
    Wenn Du keine statische Variable hast (also eine Mitgliedsvariable), dann sagt jede Instanz "jeder für sich. Das ist meine Variable."
    Bei globalen Deklarationen/Definitionen redest Du mit Herrn Kompilierer bzw. Frau Linker, ob die Bezeichner innerhalb oder auch außerhalb von Übersetzungseinheiten (also .cpp-Dateien) sichtbar sind.

    Gibt auch noch so Sonderfälle wie das hier:

    
    void MeineFunktion(void) {
    int x = 42;
    
    {
      int x = 1984;
    }
    // x mit 1984 "stirbt" hier; x mit 42 "lebt" noch. Die Lebensdauer de Variablen sind so festgelegt.
    
    }
    

    Aber hier gibt es keine doppelte Definition, da wir die x-e in verschiedenen {} haben (also in verschiedenen Gültigkeitsbereichen.

    So, bin zu Müde gerade ...
    Ich hoffe jedoch, ich war nicht allzu verwirrend.
    Wenn es Dich verwirrt, einfach ignorieren. 😉


    Bemerkungen:

    Evtl. schreibe ich noch einen C++-Leitfaden zu Gültigkeitsbereichen und Lebensdauern mit Bezugnahme des C++-Sprachstandards.
    Evtl. auch nicht.

    Ich hoffe, dass der auch nicht wie der eine Leitfaden von mir keinen Anklang findet.



  • @dozgon sagte in Klassenvariable, Instanzvariable, Lokale Variable....:

    Mit extern signalisierst Du dem Kompilierer (bzw. dem Linker), dass Du die globale Variable in einer anderen .cpp-Datei (Übersetzungseinheit) deklariert hast.

    Immer etwas fies, sich aus einem langen Text eine Stelle raus zu suchen, aber da du schon von Haarspalterei sprichst:
    "definiert" statt "deklariert" wäre richtig (deklariert wird es auch in dieser cpp) .


Anmelden zum Antworten