static Member Variable geht irgendwie nicht



  • Hallo,

    In einem etwas umfangreicheren Programm kaempfe ich gerade mit etwas, das mir eigentlich zunaechst simpler erschien, aber ich bekomme es nicht wirklich hin. Ich habe die Situation hier mit Laien-variablen nachgestellt.

    Wenn ich das ganze kompiliere (G++ 4.3.2 / Debian) bekomme ich einen Linker Error. Wie macht man, dass der Code unten compiliert? Was mach ich falsch bzw. warum geht's net? 😕

    #include <iostream>
    
    class BaseGroove
    {
    public:
      BaseGroove(int arg){ std::cout << "BaseGroove::BaseGroove( " << arg << " ) - ctor\n"; }
      void doGroove(){ std::cout << "BaseGroove::doGroove()\n"; }
    };
    
    #define ARGUMENT 777
    
    class BattleField
    {
    private:
      struct MyGroove : public BaseGroove
      {
        MyGroove() 
          : BaseGroove( ARGUMENT){ std::cout << "MyGroove::MyGroove()\n"; }
      };
    
      typedef struct MyGroove
        Groovy_t;
    
      static Groovy_t groovy;
    
    public:
      static void getStatic()
      {
        std::cout << "BattleField::getStatic()\n";
    
        // problem: ...undefined reference to 'Battlefield::groovy'
        groovy.doGroove();
      }
    };
    
    int main(){
      BattleField::getStatic();
      return 0;
    }
    


  • Statische Membervariablen müssen ausserhalb der Klasse definiert werden. Du kannst sie auch gleich dort initialisieren, musst aber nicht.

    BattleField::Groovy_t groovy;
    


  • außerdem musst du sie im cpp-File (nicht im header) anlegen (siehe Nexus' post), da du sonst Linkerfehler wegen mehrfach definierten symbolen bekommst, wenn du den header in mehr als einer cpp einbinden möchtest.



  • vlad_tepesch schrieb:

    außerdem musst du sie im cpp-File (nicht im header) anlegen (siehe Nexus' post), da du sonst Linkerfehler wegen mehrfach definierten symbolen bekommst, wenn du den header in mehr als einer cpp einbinden möchtest.

    Hmm.. verstehe das Problem jetzt nicht ganz, wenn ich es in den Header schreibe
    und einen Inlcude Guard benutze, dann wird die static Variable doch auch nur
    einmal definiert?! Ausserdem habe ich im Bsp, zB nur ein File .cpp

    Ich habe nun erfolglos ausprobiert vor und nach der Klasse BattleField die
    folgende Zeile einzufuegen (hatte ich vorher auch schon, eben auch erfolglos)

    static struct BattleField::Groovy_t groovy;
    

    Nebenbei habe ich ausprobiert, die Definition vom "MyGroove" statt "private"
    "public" zu erklaeren, habe nun ausserdem auch noch beide Klassen Forward-
    deklariert (als auch selbiges versucht mit der Inneren Klasse). Tja der Fehler
    ist immer derselbe, diesmal:

    "Groovy_t" in class "BattleField" does not name a type

    Wie gesagt, ich dachte es sei einfacher.. 😕



  • Sorry, ich hatte vorhin was falsch; so sollte es sein:

    BattleField::Groovy_t BattleField::groovy;
    

    Aber was bringt dir das typedef ?



  • Also erstmal: struct ist bis auf die Berechtigung immernoch gleich class. Der Typedef ist überflüssig.

    Fabeltier schrieb:

    Hmm.. verstehe das Problem jetzt nicht ganz, wenn ich es in den Header schreibe
    und einen Inlcude Guard benutze, dann wird die static Variable doch auch nur
    einmal definiert?! Ausserdem habe ich im Bsp, zB nur ein File .cpp

    Wenn Du aber diese Headerdatei in zwei unabhängigen Sourcen einbindest, hast Du die Definition zweimal. Da helfen auch Includeguards nicht.



  • genau und bim zusammenlinken der beiden objectdateien, wird der linker feststellen, dass da zwei symbole sind, die gleich heißen und mit nem Linker error abbrechen.



  • @Nexus
    Ich habe jetzt etwas damit herumgespielt. Ich hatte Deine Erklaerung leider etwas falsch verstanden, naemlich dass die Zeile _zusaetzlich_ ist.

    Wichtig ist also, dass man:
    1. die static Deklaration weiterhin innerhalb der Klasse steht (private oder public definition des Typs scheint irrelevant zu sein):

    static Groovy_t groovy;
    

    2. ...HINTER der Klasse muss man dann die static Variable definieren, aber ohne static, so wie Nexus das erklaert hat:

    BattleField::Groovy_t BattleField::groovy;
    

    Mein laufender Code sieht dann so aus:

    #include <iostream>
    
    class BaseGroove
    {
    public:
      BaseGroove(int arg){ std::cout << "BaseGroove::BaseGroove( " << arg << " ) - ctor\n"; }
      void doGroove(){ std::cout << "BaseGroove::doGroove()\n"; }
    };
    
    #define ARGUMENT 777
    
    class BattleField
    {
    private:
      struct MyGroove : public BaseGroove
      {
        MyGroove()
          : BaseGroove( ARGUMENT){ std::cout << "MyGroove::MyGroove()\n"; }
      };
    
      typedef struct MyGroove
        Groovy_t;
    
      static Groovy_t groovy;
    
    public:
      static void getStatic()
      {
        std::cout << "BattleField::getStatic()\n";
    
        // jetzt laeufts!
        groovy.doGroove();
      }
    };
    
    BattleField::Groovy_t BattleField::groovy;
    
    int main(){
      BattleField::getStatic();
      return 0;
    }
    

    Wahrscheinlich war fuer mich deshalb die Aufteilung in .cpp und .hpp File etwas verwirrend. Nja, ich denke es ist ja klar, dass wen ich etwas auf zwei Files aufteile ich es trotzdem nur einmal definieren werde und nicht re-definiere, oder? Das meinte ich auch nicht mit dem Include Guard, mir war hier nicht klar, dass man eben die obigen 2 Zeilen braucht und es um deren Aufteilung geht.

    vlad_tepesch schrieb:

    genau und bim zusammenlinken der beiden ...

    Ja und genau... 😉
    Ok, ok, ok, das typedef duerft Ihr auch weglassen, wenn Ihr wollt! 😉 Ich hatte die Diskussion ja erst und hab das mittlerweile schon begriffen. Das typedef befindet sich hier im Code, weil... ich es einerseits aus einer C-Gewohnheit verwende,.. weil ich es im Original auch so benutze, und da hauptsaechlich um einen Typ zu bekommen, der sich irgendwie "..._t" nennt. Auch eine Gewohnheit. Aber das ist doch eigentlich auch total egal fuer das Problem hier, oder?! Genau!

    Danke Euch allen fuer die Beantwortung!!! :xmas1: :xmas2:


Anmelden zum Antworten