Klasseninstanzen global deklarieren



  • Hi,

    ich brauche in einer Klasse X einen globalen Vektor mit Pointern auf Image-Objekte. Den Vektor habe ich in der Header-Datei deklariert:

    vector<Image*> images;
    

    Die Image-Klasse hat als einzigen Konstruktur

    Image(Dateipfad)
    

    in dem das Bild geladen wird.

    Damit nun die Pointer im Vektor global gültig sind, müssen auch die einzelnen Image-Objekte global gültig sein, richtig?
    Also möchte ich nun die Image-Objekte in der header-Datei global deklarieren ohne deren Konstruktor aufzurufen (dann kommt nämlich der Fehler "error: expected identifier before string constant" - ist wohl in header-Datei nicht erlaubt?). Wenn das klappt kann ich dann die Images im Konstruktor der Klasse X instanzieren und den Vektor füllen.

    Hat jemand einen Tipp?

    Grüße



  • Zeig doch mal den genauen Code, der den Fehler verusacht hat, dann können wir dir auch weiterhelfen.

    Ansonsten:
    Du hast dort gar keine Image-Objekte angelegt, sondern nur einen (anfangs leeren) Vektor, der Zeiger auf Image's aufnehmen kann. Der könnte im weiteren Verlauf des Programms dann gefüllt werden.
    Allerdings ist diese Definition im Header fehl am Platz (und wird deinen Linker aus dem Konzept bringen, sobald du den Header an mehr als einer Stelle einbindest).



  • Gut aber wohin gehört die Definition, damit die Objekte trotzdem global verfügbar sind?

    Dies ist der Versuch, den Vektor schon im Header zu füllen (beschränkt auf 1 Bild)

    vector<Image*> images;
    Image i1("I.jpg");
    images.push_back(&i1);
    

    Da kommt für die zweite Zeile der Fehler:

    VR.hpp:49: error: expected identifier before string constant
    VR.hpp:49: error: expected ‘,’ or ‘...’ before string constant
    

    und für die dritte:

    VR.hpp:50: error: ISO C++ forbids declaration of ‘images’ with no type
    


  • Aus dem Fragment kann ich nicht viel ableiten, ohne zu wissen, was sich hinter Image verbirgt (und ob der Compiler den Typ dort kennt).
    Die dritte Zeile ist aber definitiv falsch - Anweisungen dürfen nicht auf globaler Ebene im Raum stehen, sondern nur im Inneren einer Funktion.

    Edit:

    Gut aber wohin gehört die Definition, damit die Objekte trotzdem global verfügbar sind?

    In einer eigene CPP-Datei - in den Header packt du eine Deklaration ( extern )



  • Danke für die schnelle Antwort - ich werd bald wahnsinnig 😕

    CStoll schrieb:

    Die dritte Zeile ist aber definitiv falsch - Anweisungen dürfen nicht auf globaler Ebene im Raum stehen, sondern nur im Inneren einer Funktion.

    Deswegen hatte ich zunächst auch die push_back-Anweisung in meinem Konstruktor. Dann kommt allerdings der Fehler:

    ISO C++ forbids taking the address of an unqualified or parenthesized non-static member function to form a pointer to member function.  Say ‘&VR::i1’
    

    Du meinst ich soll die Images als extern in einer neuen hpp-Datei deklarieren und in der entsprechenden .cpp instanzieren? Aber ich will ja keine neue Klasse anlegen..!?



  • Du kannst die Definitionen auch in eine vorhandene CPP-Datei reinpacken (ich weiß ja nicht, was du vorhast, aber eventuell macht die Image.cpp oder die Main.cpp dafür Sinn).

    Um die Fehler genauer analysieren zu können, benötigen wird auf jeden Fall mehr Code.



  • Mehr relevanter Code ist eigtl gar nicht dabei.

    Ich kenne es halt aus Java so:
    Deklaration (global): Image i;
    Instanzierung (egal wo): i = new Image("bild.jpg");

    Deswegen ist dieser Versuch für mich am intuitivsten:
    In der header-Datei i1 global bekannt machen:

    vector<Image*> images;
    extern Image i1;
    

    Im Konstruktor dann instanzieren und Pointer in Vektor packen:

    Image i1("bild.jpg");
    images.push_back(&i1);
    

    Dabei kommt leider der Fehler:

    VR.hpp:49: error: storage class specified for ‘i1’
    

    Ich fürchte auch dass das extern-Schlüsselwort dort fehl am Platze ist aber ohne extern geht es nicht weil Image keinen Defaultkonstruktor hat.

    Das muss doch irgendwie möglich sein in C++ argh



  • Das geht durchaus, man muss aber höllisch mit der Initialisierungsreihenfolge und Gültigkeitsbereichen aufpassen. Denkbar wäre etwa Folgendes:

    // Header
    extern std::vector<Image*> images;
    
    // .cpp
    std::vector<Image*> images;
    
    namespace {
      Image images_obj[] = {
        Image("foo"),
        Image("bar"),
        Image("baz")
      };
    
      template<typename T, std::size_t N>
      std::size_t array_size(T(&)[N]) { return N; }
    
      struct images_initializer_class {
        images_initializer_class() {
          images.reserve(array_size(images_obj));
          for(std::size_t i = 0; i < array_size(images_obj); ++i) {
            images.push_back(&images_obj[i]);
          }
        }
      } images_initializer;
    }
    

    Einfacher wäre es natürlich, einen std::vector<Image> zu benutzen - jedenfalls, wenn Image kopierbar ist. In dem Fall könnte das so aussehen:

    // Header
    std::vector<Image> images;
    
    // .cpp
    namespace {
      Image images_obj[] = {
        Image("foo"),
        Image("bar"),
        Image("baz")
      };
    
      template<typename T, std::size_t N>
      std::size_t array_size(T(&)[N]) { return N; }
    }
    
    std::vector<Image> images(images_obj, images_obj + array_size(images_obj));
    

    Allerdings ist die Benutzung globaler Objekte generell eine fragwürdige Designentscheidung. Vielleicht magst du etwas genauer beschreiben, was du eigentlich zu erreichen versuchst. Mich beschleicht der Verdacht, dass du es dir unnötig schwer machst.



  • Die Images direkt in den Vektor zu legen hatte ich auch schon probiert. Das funktionierte aber nicht. Ich vermute, weil die Images alle eine verschiedene Größe haben... Für mich sieht es so aus, ob dieses Problem jedoch in deinem Beispiel behoben wird à la "reserve(array_size...)" etc.

    Es geht um OpenGL - die Texturen sollten zu Beginn geladen werden um spätere Ladezeiten zu vermeiden. Jetzt habe ich aber herausgefunden, dass man die Bilder nur einmal an OpenGL übergeben muss und ich sie global nicht mehr benötige - um den Rest kümmert sich dann OpenGL.

    Danke & Gruß



  • In C++0x könntest du zur Initialisierung noch eine Initialisierungsliste verwenden, das funktioniert so: http://ideone.com/TEqma

    (Mit einem GCC 4.6 kannst du zur Ausgabe sogar das Range-based for verwenden, falls die Größe bekannt ist, das ginge so: http://ideone.com/QS4gz aber der Compiler da kann das leider noch nicht, daher kommen die Fehler.)


Log in to reply