Collection in C++?



  • Wenn du einen vector von Vektoren wolltest, dann ist das so korrekt.





  • Hey,
    vielen Dank auch dafür. 🙂 Ich fürchte jetzt wo es korrekt ist, ist es noch nicht ganz das, was ich eigentlich suche. Diese vector-Sache scheint mir doch ein wening statisch zu sein. Man muss einen festen Umfang von Elementen definieren und das kann ich nicht immer. Was ich gern hätte beschreibt die MSDN Library (VB) folgendermaßen:

    Das Collection-Objekt bietet eine einfache Möglichkeit, um auf eine verwandte Gruppe von Elementen als einzelnes Objekt Bezug zu nehmen. DieElemente in einer Auflistung müssen nur durch die Tatsache miteinander in Beziehung stehen, daß sie sich in derAuflistung befinden. Es ist nicht erforderlich, daß Elemente einer Auflistung denselben Datentyp haben.

    Eine Auflistung kann genauso erstellt werden wie andere Objekte. Beispiel:

    Dim X As New Collection

    Nachdem die Auflistung erstellt wurde, können ihr mit der Add-Methode Elemente hinzugefügt werden, und mit der Remove-Methode können Elemente entfernt werden. Mit der Item-Methode können bestimmte Elemente aus der Auflistung abgerufen, während die gesamte Auflistung mit der For Each...Next-Anweisung durchlaufen werden kann.

    Mit so einer Collection kann man sich in dann eine Collection-Klasse basteln, die dann Instanzen anderer Klassen "sammelt". (Angelehnt an dieses Beispiel: http://www.vbarchiv.net/workshop/workshop37.php). Das sieht dann ungefähr so aus:

    'Dies ist die Collection-Klasse für Instanzen der Klasse cls_ItemRespawn
    
    Private mCol As Collection	'Das klasseninterne Collection-Objekt
    
    _________________________________
    Public Function AddRespawnLocation(ByVal MazeX As Integer, ByVal MazeY As Integer, Quality As Byte) As cls_ItemRespawn 'Neue Instanz hinzufügen und 
    															dabei Daten für selbige aufnhemen
    
    Dim objNewMember As cls_ItemRespawn	
        Set objNewMember = New cls_ItemRespawn	'Temporäre Instanz erstellen
    
      With objNewMember	'Daten zuweisen
            .MazeX = MazeX
            .MazeY = MazeY
            .Quality = Quality
      End With
    
      mCol.Add objNewMember	'Der Collection hinzufügen
      Set AddRespawnLocation = objNewMember '(...muss nicht sein)
      Set objNewMember = Nothing	'Temporäre Instanz löschen
    End Function
    _________________________________
    Public Property Get Item(ByVal Index As Variant) As cls_ItemRespawn 'Zugriff auf Elemente ermöglichen 
    			'(Variant für den Fall, dass ein Key-String für ein Element übergeben wurde)
     Set Item = mCol.Item(Index)
    End Property
    _________________________________
    Public Property Get Count() As Long
      Count = mCol.Count
    End Property
    _________________________________
    Public Sub Remove(ByVal Index As Integer)
      mCol.Remove Index
    End Sub
    _________________________________
    Private Sub Class_Initialize()
      Set mCol = New Collection
    End Sub
    _________________________________
    Private Sub Class_Terminate()
      Set mCol = Nothing
    End Sub
    

    Das schöne daran ist, dass man auch die collection-Klasse wieder in einer collection sammeln kann und dadurch eine gewisse Hierarchie in die Objekte bekommt.

    'Anwendungsbeispiel:
        Dim Gameframes As cls_GameFrameCollection
        Set Gameframes = New cls_GameFrameCollection
    
        With Gameframes
            .AddGameFrame "Maze", 5, 55, 795, 700, True 'neues Unterobjekt erstellen
                .Item("Maze").AddSurfaceLayer "Ground"  'Zugriff auf Unterobjekt / neues Unterobjekte im Unterobjekt hinzufügen
                .Item("Maze").AddSurfaceLayer "Focussing"
                '...
            .AddGameFrame "Textures", 5, 55, 700, 605, False
                .Item("Textures").AddSurfaceLayer "RawTextures"
            .AddGameFrame "MemoryUsage", 405, 5, 555, 25, True
            '...
        End With
    
        Gameframes.Item(1).Item(1).hasColorkey  'Zugriff auf Unterelemente über Indizes
        Gameframes.Item("Textures").Item("RawTextures").hasColorkey 'Zugriff auf Unterelemente über Namen
        Gameframes.Item(1).Remove ("Textures")  'Entfernen
    

    Dabei ist die Zahl der jeweiligen Unterobjekte dynamisch änderbar. Man legt nicht vorher fest, wie viele maximal gespeichert werden. Bei diesem Beispiel wäre das noch übersichtlich, weil es je Stufe maximal 10 Unterobjekte geben würde. Das wären dann allerdings schon 110 Instanzen für die Speichert reserviert wäre, wobei es hier tatsächlich nur 18 sind, da manche Unterobjekte auf der ersten Stufe gar keine weiteren Unterobjekte enthalten.

    Es ist bestimmt möglich, in C++ die Größe des Vektors an die Zahl der Instanzen anzupassen indem man den Speicher neu festlegt, aber dazu bin ich mit meinem Anfängerwissen nicht in der Lage. Außerdem habe ich noch Hoffnung, dass es auch für C++ eine bequemere Variante gibt. 🙂 Oder gibt es möglicherweise eine ganz andere Herangehensweise an das Problem?
    MfG

    Sven



  • Die Zahl der Elemente in einem std::vector ist genauso dynamisch. Jedes mal wenn du ein Element mit push_back hinzufügst, wächst der vector in seiner Größe um 1. Das geschieht völlig automatisch und gilt auch für alle anderen Container in der STL. War das dein Problem?

    Du musst dir auch keine eigene Collection-Klasse basteln wie in VB6. Wenn du eine Collection von ints willst, schreibst du std::vector<int>.



  • Okay... so langsam fängt es an Spaß zu machen. Jetzt habe ich gerade das hier zusammengeschrieben und zumindest der Zugriff scheint zu klappen. Für das erase hab ich schon zwei Versionen gefunden, die nicht funktionieren. 😉

    #include <iostream>
    #include <vector>
    #include "Vektor.h"
    using namespace std;
    
    int main()
    {
    	vector<Vektor> a;
    	Vektor b;
    	b.set_x (3);
    	a.push_back (b);
    	b.set_x (5);
    	a.push_back (b);
    	b.set_x (8);
    	a.push_back (b);
    	cout << a.at(0).get_x();
    	cout << a.at(1).get_x();
    	cout << a.at(2).get_x();
    	 a.erase(1); //geht nicht
    	 a.erase(a.at(1)); //geht auch nicht
         a.erase(0); //stürzt fürchterlich ab
    	cout << a.at(1).get_x();
    	return 0;
    };
    

    Wie schaffe ich es, ein bestimmtes Element zu löschen? und vor allem: Wie wirkt sich das auf die Indizes aus? Ist der Index weg oder werden die Indizes wie in Vb der Reihenfolge nach neu vergeben?

    Und außerdem: Kann man zu einem Index noch ein Schlüsselwort vergeben oder muss man sich das manuell erprogrammieren?



  • Was heißt "geht nicht"? - Ich habe gerade keinen C++-Compiler da. erase() erwartet einen iterator, ich weiß gerade nicht auswendig, ob ein Index in einen Iterator umgewandelt werden kann. Die Indizes werden auf jeden Fall neu vergeben.

    Und außerdem: Kann man zu einem Index noch ein Schlüsselwort vergeben oder muss man sich das manuell erprogrammieren?

    Du hast die Möglichkeit eine Map zu verwenden. Dann kannst du zum Beispiel bei einer map<std::string, Vektor> so den passenden Vektor holen: map["blabla"].



  • bei 'a.erase(1); ' hieß geht nicht:

    error C2664: 'class Vektor *__thiscall std::vector<class Vektor,class std::allocator<class Vektor> >::erase(class Vektor *)' : Konvertierung des Parameters 1 von 'const int' in 'class Vektor *' nicht moeglich. Die Konvertierung eines ganzzahligen Typs in einen Zeigertyp erfordert ein reinterpret_cast-Operator oder eine Typumwandlung im C- oder Funktionsformat

    bei 'a.erase(a.at(1));' hieß es:

    error C2664: 'class Vektor *__thiscall std::vector<class Vektor,class std::allocator<class Vektor> >::erase(class Vektor *)' : Konvertierung des Parameters 1 von 'class Vektor' in 'class Vektor *' nicht moeglich. Kein benutzerdefinierter Konvertierungsoperator verfuegbar, der diese Konvertierung durchfuehren kann, oder der Operator kann nicht aufgerufen werden
    Fehler beim Ausführen von cl.exe.

    Ich habs gerade so gelöst: a.erase(a.begin() + 1);

    Vielen Dank nochmal. Das mit der Map werde ich demnächst auch probierenm, klingt nach einer guten Lösung.

    MfG
    Sven



  • nim CArray!!

    CArray<deinObjektTyp,deinObjektTyp> arraylist;

    deinObjektTyp a;
    deinObjektTyp b;
    deinObjektTyp c;

    arraylist.add(a);
    arraylist.add(b);
    arraylist.add(c);

    arrayLisr.RemoveAt(INDEX);



  • Hey ho!

    CArrey klingt auch nicht schlecht.... ich habe gerade mit

    CArray<Vektor,int> VList; //(stimmt das so?)
    

    versucht etwas zu erstellen, aber es geht noch nicht ("error C2065: 'CArray' : nichtdeklarierter Bezeichner"). Kann das daran liegen, dass ich mit einer Konsolenanwenung arbeite? Kann ich CArray über irgendein #include nutzbar machen / sollte ich ganz auf MFC umsteigen?



  • Wenn Du in einem MFC-Forum postest, gehat man eigentlich davon aus, dass Du MFC verwendest...
    Wenn Du ein Konsolen-Projekt hast, kannst Du beim Erzeugen auch angeben, ob Du MFC haben willst.
    Beim Umstellen von Hand musst Du ein paar Projektsettings machen und die Includes einbinden... (müsste jetzt aber auch zuerst eines mit dem Wizar angelegen, dann würde ich sehen was man machen muss).

    Ansonsten nimm doch "std::vector". Was geht denn damit nicht?



  • Naja, ich hatte auf der Startseite einfach auf Visual C++ geklickt und war hier gelandet, ohne überhaupt zu wissen was MFC ist. 😉 So kam das...

    std::vector geht auch, ich wollte nur beide mal ausprobieren, vor allem, weil mir der zweite noch etwas praktischer erschien...

    Was ist eigentlich der Unterschied zwischen MFC und einer Win-32-Anwendung? Ist MFC mehr für das bearbeiten von Dateien vorgesehen?





  • Hmm, den hatt ich schon überflogen, aber danke trotzdem. 🙂


Anmelden zum Antworten