Array von Klassen initialisieren



  • Hi

    Es geht um was simples: ich habe eine Klasse Auto geschrieben, jetzt könnte ich in der main mittels:

    auto a(4,6); //Argumente: Alter des Autos, Anzahl Sitzplätze
    

    ein neues auto erstellen.
    Nun brauche ich aber nicht eines, sondern 5 Autos, also werd ich ein Array brauchen. Jedoch will das nicht, ich habe es auf folgende Arten versucht:

    auto a[5];
    //oder
    auto a[5]=new auto(4,6);
    //oder
    auto a[5]=new auto;
    

    Kompilerfehler sehen immer ähnlich aus:

    main.cc:84: error: conversion from ‘auto*’ to non-scalar type ‘auto’ requested
    
    //oder auch:
    
    No matching function to call auto::auto()
    candidates are....
    

    Daher: wie funktioniert das richtig?



  • auto ist ein Schlüsselwort der C++-Syntax. Man benutzt es, um Stackvariabeln zu deklarieren, aber es ist eigentlich so gut wie überflüssig.

    Schreib doch Auto gross oder nimm einen anderen Namen, denn auto ist reserviert.



  • Ist dir aufgefallen, dass das Wort "auto" blau erscheint?

    auto ist ein keyword, reserviert von C++, damit deklariert man Variablen als automatische Variablen (das ist der Normalfall, wenn du nichts schreibst sind deine Variablen auto), im Gegensatz z.B. zu static Variablen.

    Nenn deine Klasse Auto oder PKW der so, dann sollte es gehen 😋



  • const int ANZAHL = 5;
    
    //erstellen
    Auto **autos = new Auto[ANZAHL];
    autos[0] = new Auto(4,6);
    autos[1] = new Auto(0,2);
    //...
    
    //verschrotten
    for(size_t i = 0; i < ANZAHL; ++i)
        delete autos[i];
    delete [] autos;
    


  • erstellen war falsch. so gehts:

    Auto **autos = new Auto*[ANZAHL];
    


  • velo schrieb:

    const int ANZAHL = 5;
    
    //erstellen
    Auto **autos = new Auto[ANZAHL];
    autos[0] = new Auto(4,6);
    autos[1] = new Auto(0,2);
    //...
    
    //verschrotten
    for(size_t i = 0; i < ANZAHL; ++i)
        delete autos[i];
    delete [] autos;
    

    Warum machst du es mit Zeigern, sogar das Array ist auf dem Heap? Zeiger machen meistens nur alles komplizierter, deshalb würde ich zu statischem Speichergebrauch raten:

    Auto MeineAutos[5];
    MeineAutos[0].Auto(4, 6); // oder
    MeineAutos[1] = Auto(0, 2);
    
    // verschrotten ist nicht mehr nötig
    


  • Nexus schrieb:

    Warum machst du es mit Zeigern, sogar das Array ist auf dem Heap?

    Weil sein Auto keinen Standardkonstruktor hat.



  • Nexus schrieb:

    Auto MeineAutos[5];
    MeineAutos[0].Auto(4, 6); // oder
    MeineAutos[1] = Auto(0, 2);
    

    Nein. Variante 1 bitte nicht benutzen! (Unzulässig)
    Man darf den Konstruktor eines Objektes nicht nachträglich aufrufen.
    Die Zuweisung wiederum ist zulässig.

    Wobei ich eh statt einem Array zu einem Vector greifen würde:

    #include <vector>
    //...
    std::vector<Auto> autos;
    autos.push_back(Auto(4, 6));
    autos.push_back(Auto(0, 2));
    // ...
    


  • Danke Velo, aber es funktioniert nicht richtig:

    autos **a = new autos[2];
    
    a[0] = new autos(4,6);
    a[1] = new autos(8,8);
    

    So hab ich das jetzt, Fehlermeldungen für jede Variable in der Klasse!

    request for member blablabla, which is of non-class type ‘autos*’
    
    //UND beim initialisieren:
    
    main.cc:84: error: cannot convert ‘autos*’ to ‘autos**’ in initialization
    main.cc:86: error: expected constructor, destructor, or type conversion before ‘=’ token
    

    Was mache ich falsch?



  • P.S: Alternative ist z.B. boost::ptr_vector<Auto> [Siehe auch Boost, Pointer Container]



  • ok hab jetzt den vorschlag mit vektor ausprobiert, Der fehler mit
    "request for member..." ist jetzt weg, aber
    beim push_backen gibt er mir aus:

    main.cc:90: error: expected constructor, destructor, or type conversion before ‘.’ token
    main.cc:9
    


  • autos** a ist ein Pointer auf Pointer auf autos. du kannst einem Pointerpointer kein Objekt zuweisen, nur einem Klassenpointer...still with me? 😉

    Du müsstest also a ein Array aus Pointern zuweisen:

    a = new autos*[4];
    autos[0] = new autos;
    autos[1] = new autos;
    .
    .
    .



  • Autonom schrieb:

    Danke Velo, aber es funktioniert nicht richtig

    komisch, bei mir gehts 😉

    #include <iostream>
    using namespace std;
    
    class Auto
    {
    public:
    	Auto(size_t alter, size_t anzSitze);
    
        size_t zeigeAlter() const;
        size_t zeigeAnzahlSitze() const;
    
    private:
        size_t m_alter, m_anzSitze;
    };
    
    //Implementierung
    
    Auto::Auto(size_t alter, size_t anzSitze)
    : m_alter(alter), m_anzSitze(anzSitze)
    {
    }
    
    size_t Auto::zeigeAlter() const
    {
        return m_alter;
    }
    
    size_t Auto::zeigeAnzahlSitze() const
    {
        return m_anzSitze;
    }
    
    //Hauptteil
    
    int main()
    {
        const int ANZAHL = 5;
    
        //erstellen
        Auto **autos = new Auto*[ANZAHL];
        autos[0] = new Auto(4,6);
        autos[1] = new Auto(0,2);
        //...
    
        cout << "Das erste Auto ist " << autos[0]->zeigeAlter() << " Jahre alt.\n";
        cout << "Das zweite Auto hat " << autos[1]->zeigeAnzahlSitze() << " Sitze." << endl;
    
        //verschrotten
        for(size_t i = 0; i < ANZAHL; ++i)
            delete autos[i];
        delete [] autos;
    }
    


  • asc@ausgeloggt schrieb:

    Nein. Variante 1 bitte nicht benutzen! (Unzulässig)
    Man darf den Konstruktor eines Objektes nicht nachträglich aufrufen.

    Tut mir leid, dass ich hier Unsinn verbreite. Ich selber benutze eigentlich (wenn ich überhaupt in eine solche Situation komme) auch die Zuweisung, aber ich dachte, das andere wäre legitim. Danke für die Berichtigung!

    Und einigen wir uns darauf, mit std::vector geht das definitiv am einfachsten 😉

    velo schrieb:

    Nexus schrieb:

    Warum machst du es mit Zeigern, sogar das Array ist auf dem Heap?

    Weil sein Auto keinen Standardkonstruktor hat.

    Du meinst, keinen spezifischen Standardkonstruktor, der die Membervariabeln initialisiert. Wenn kein eigener implementiert wurde, wird ein Standardkonstruktor vom Compiler erstellt.

    An der Stelle fände ich die Implementation eines Standardkonstruktors aber wesentlich einfacher und auch zukunftssicherer als ein Zeigerarray aus Zeigern.



  • 1. Vektor wäre mir lieber als Array (wäre aber auch damit zufrieden)

    ich hab's jetzt mit Vektor probiert, genauso wie es asc vorgeschlagen hat, wie gesagt, er packt den push_back nicht.

    Kann es sein, dass

    std::vector<Auto> autos;
    

    falsch ist?



  • Autonom schrieb:

    Kann es sein, dass

    std::vector<Auto> autos;
    

    falsch ist?

    Diese Zeile ist schon richtig, aber könntest du mal den ganzen Code inklusive Fehlermeldungen zeigen? Hast du <vector> inkludiert?



  • Der ganze Code wäre viel zu riesig, aber alle relevanten Teile:

    //main
    #include <vector>
    #include <iostream>
    #inlcude <autos.h>
    
    using namespace std;
    
    vector<autos> a;
    a.push_back(autos(4, 6));
    a.push_back(autos(0, 2));
    
    //autos.h
    
    #ifndef _AUTOS_
    
    #define _AUTOS_
    
    class autos
    
    {
    
    public:
    
    	autos(int alter, int sitze);
    
    private:
            int alter;
            int sitze;
    };
    
    #endif
    


  • Hmmmm .... jetzt wären noch hilfreich:
    - die Fehlermeldung
    - soll "a" ein globales Objekt sein ? Befinden sich die a.push_back()-Anweisungen innerhalb einer Funktion (z.B. main()) ?

    BTW: autos ist ein wenig irreführend.... (wenn auch nur eine Kleinigkeit)

    Gruß,

    Simon2.



  • Autonom schrieb:

    #inlcude <autos.h> // Schreibfehler...
    
    vector<autos> a;
    a.push_back(autos(4, 6));  // ist das alles in der main()-Funktion?
    a.push_back(autos(0, 2));  // Global darfst du das nämlich nicht machen
    

    Und wie stehts mit deiner Klasse? Ist der Standardkonstruktor irgendwo definiert?


  • Mod

    Nexus schrieb:

    velo schrieb:

    Nexus schrieb:

    Warum machst du es mit Zeigern, sogar das Array ist auf dem Heap?

    Weil sein Auto keinen Standardkonstruktor hat.

    Du meinst, keinen spezifischen Standardkonstruktor, der die Membervariabeln initialisiert. Wenn kein eigener implementiert wurde, wird ein Standardkonstruktor vom Compiler erstellt.

    Nur wenn kein anderer Konstruktor vom Nutzer deklariert wurde. Da aber nach Voraussetzung ein Konstruktor mit zwei Argumenten existiert, und der offensichtlich nicht vom Compiler stammen kann, wird der Compiler keinen Defaultkonstruktor deklarieren.
    Ein Array-new-Ausdruck kann keinen spezifischen Kosntruktor aufrufen, lediglich wenn der betreffende Typ ein POD ist (hier nicht der Fall), besteht die Wahl zwischen Value-Initialisierung bzw. keiner Initialisierung. Ein statisches oder automatisches Array kann dagegen über eine Aggregatinitialisierungsliste initialisiert werden. Standardkontainer erlauben dagegen erheblich größere Freiheiten bei der Initialisierung.


Anmelden zum Antworten