zeigertyp zur laufzeit ändern?



  • Schau dir mal std::vector und Vererbung an und mach dann sowas.

    std::vector<BaseClass*> inhalt.
    

    Und wenn du es ganz schön machen willst, dann nimm share Pointer oder ähnliches.



  • Titel_ schrieb:

    Und wenn du es ganz schön machen willst, dann nimm share Pointer oder ähnliches.

    Wieso ist das dann ganz schön?



  • Also ersteinmal, new gibt ein zeiger zurück.
    Also selbst wenn es keine Probleme gäbe:
    mit

    void * inhalt = new A[10];
    

    wird nun speicher reserviert wie du auch sagtest, doch hier:

    inhalt[0] = new A;
    

    reservirst du wieder komplett neuen speicher und versuchst den Zeiger der auf diesen Speicher zeigt an die Stelle zu speichern wo eine Instanz dieser klasse hingehört.
    Da ganze funktioniert wenn du das so machst:

    void * inhalt = new A[10];
    
    ((A*)inhalt)[0] = A();
    

    Doch würde ich dir eher dazu raten, dann doch lieber mit Basisklassen zu arbeiten oder eine andere Möglichkeit zu finden.



  • David_pb schrieb:

    Titel_ schrieb:

    Und wenn du es ganz schön machen willst, dann nimm share Pointer oder ähnliches.

    Wieso ist das dann ganz schön?

    Kein Speicher von Hand freigeben -> keine Memleaks, wenn ams nicht extrem dumm macht.


  • Administrator

    tenim schrieb:

    im konstruktor einer klasse möchte ich ein array von objektzeigern einer anderen klasse anlegen. ich kenne aber erst im konstruktor
    a) die anzahl der arrayelemente und
    b) die klasse, deren objektzeiger ich speichern will.

    Das klingt für mich perfekt nach einem Fall von Forward Declaration.

    Bar.hpp

    class Bar
    {
      /* ... */
    };
    

    Foo.hpp

    class Bar; // Forward declaration
    
    class Foo
    {
    private:
      Bar* m_barArray;
    
    public:
      Foo(unsigned int barCount);
    };
    

    Foo.cpp

    #include "Foo.hpp"
    #include "Bar.hpp"
    
    Foo::Foo(unsigned int barCount)
    {
      // Erst hier ist die Anzahl an Elementen bekannt,
      // sowie die Klasse Bar.
      m_barArray = new Bar[barCount];
    
      // Im Destruktor nicht vergessen, die Sache zu löschen.
      // Oder gleich einen std::vector nehmen.
    }
    

    Grüssli



  • ich habs jetzt so gemacht:

    int **inhalt;
    

    dann zur laufzeit im konstruktor:

    inhalt=(int**)malloc(4*AnzahlElemente);  //nötigen gesamtspeicher für alle zeiger reservieren
    for(i=0;i<AnzahlElemente;i++) inhalt[i]=(int*)new A();
    

    dann muss ich es nur noch irgentwie hinkriegen, durch casts auf die memberfunktionen von z.b. inhalt[3] zuzugreifen. also z.b.

    inhalt[3]->machWas();

    edit:

    A *z;
    z=(A*)inhalt[3];
    
    z->machWas()
    

    leider kommt dann die meldung, das die memberfunktion "inaccessable" ist, obwohl public?!



  • WTF?

    Schau dir lieber Draveres Vorschlag an. So wird da nie was draus.. 🙄



  • wiso wtf? was ist an meinem code falsch?

    das beispiel von Dravere geht bei mir nicht. er deklariert in seiner
    foo.hpp bereits das array vom typ Bar.

    "Bar* m_barArray;"

    aber dort weiss ich ja noch nicht, was für einen zeiger ich brauche. es könnte genausogut ein zeiger auf das objekt "Auto" sein.

    ich kann nichts deklarieren -egal wo, dessen typ erst zur laufzeit klar ist.


  • Administrator

    tenim schrieb:

    wiso wtf? was ist an meinem code falsch?

    Weil es ein äusserst hässliches rumgefrickel ist. Sowas hat man vielleicht in C gemacht, in C++ gibt es dazu andere Möglichkeiten.

    Es gibt viele Möglichkeiten, von Basisklasse bis hin zu Templates. Aber das was du machst ist nicht nur hässlich, sondern sogar extrem Fehleranfällig.

    Ich würde vorschlagen, dass du dein Problem etwas genauer erläuterst, ich bin mir sicher, wir finden eine deutlich bessere Lösung.

    Grüssli



  • Dravere schrieb:

    tenim schrieb:

    wiso wtf? was ist an meinem code falsch?

    Weil es ein äusserst hässliches rumgefrickel ist. Sowas hat man vielleicht in C gemacht, in C++ gibt es dazu andere Möglichkeiten.

    Nicht einmal. In C wäre das rein mit malloc gemacht worden und nicht auch noch mit new ebenfalls.. Ich möchte gar nicht wissen, wo und wie er das wieder freigibt.. 🙄



  • ich hab es jetzt schöner lösen können:

    da meine mir bisher unbekannten klassen alle von einer basisklasse A erben, sind diese ja zuweisungskompatibel, wenn ich bei der vererbung "public" angebe(hatte ich vergessen bzw. bis jetzt nicht gewusst -komme von der java ecke).

    so brauche ich mir jetzt keine sorgen mehr zu machen, ich kann im konstruktor
    einfach schreiben

    inhalt **A;

    und nach dem erzeugen der objekte B,C,D (welche ja von A erben), kann ich die objektreferenzen trotzdem zuweisen, weil halt zuweisungskompatibel.

    inhalt[1]=new B();

    hintergrund:
    ich schreibe einen raumschiffsimulator, der im perryversum angesiedelt ist. 🙂

    es ging im detail darum, das ich eine basisklasse "Energieerzeuger" habe, von der alle "echten" energieerzeuger wie z.b. Fusionsreaktoren oder Schwarzschildgeneratoren abgeleitet sind. die klasse "Energieerzeuger" dient somit nur der bereitstellung von eigenschaften und methoden, die jeder echte
    "Energieerzeuger" hat. die beiden obengenannten "Energieerzeuger" sind aktive, also sie erzeugen selbst energie. ausserdem gibt es eine klasse kraftwerk, welches aus mehreren aktiven Energieerzeugern besteht und selbst passiv ist(weil es ja keine energie aus eigener kraft erzeugt). auch die klasse kraftwerk ist von der basisklasse "Energieerzeuger" abgeleitet, da diese auch diese eigenschaften hat.

    jetzt das problem:
    erst zur laufzeit, also wenn bekannt ist was für ein raumschiff-modell gewählt wurde, kann ich anfangen, mehrere kraftwerk-objekte in dem schiff zu platzieren.
    dabei muss ich im konstruktor des kraftwerks natürlich angeben
    a) welcher typ von energieerzeuger verbaut werden soll und
    b) wieviele davon

    ich habe allerdings schon im konstruktor des kraftwerks eine variable mit dem zukünftigen array von "Energieerzeuger"-objekten angelegt. das kann ich dann später durchiterieren, egal was für ein typ von kindobjekt darin gefunden wird.
    eben:

    Energieerzeuger  **pEnergieerzeuger;
    

    dieses array muss ich dann

    1. initialisieren:

    pEnergieerzeuger=(Energieerzeuger**)malloc(4*cAnzahl);
    

    (da jeder zeiger 4 byte braucht(im 32bit system) reserviere ich 4*anzahl.)

    2. objekte zuweisen:
    (eEt ist ein enum mit den typen der erzeuger, die anderen varianten hab ich noch nicht programmiert)

    for(i=0;i<cAnzahl;i++)
    	{
    		switch (eEt)
    		{
    			case FusionsreaktorTerraTyp1:
    				pEnergieerzeuger[i]=new Fusionsreaktor_Terra_Typ1(i+1);
    				break;
    		}
    	}
    

    3. nutzen des objektes

    pEnergieerzeuger[1]->fahreHoch();
    

    scheint jetzt soweit alles zu klappen.
    🙂

    bin natürlich für elegantere lösungen dankbar.



  • hey mr. "drakon"

    ich habs in meinem letzten post bereits mit malloc gemacht.
    deine überhebliche art kannst du dir sparen. du bist nicht der einzige, der programmieren kann. ich bin bestimmt kein c++ crack, aber ich machs ja erst seit 2 tagen i n c++.

    p.s.

    freigben tue ich das so:

    free(pEnergieerzeuger);



  • tenim schrieb:

    deine überhebliche art kannst du dir sparen. du bist nicht der einzige, der programmieren kann. ich bin bestimmt kein c++ crack, aber ich machs ja erst seit 2 tagen i n c++.

    Das hat mit Überheblichkeit nix zu tun.
    In C++ macht man solche Sachen mit new und delete, egal was du früher gemacht hast. Denn mit new und delete bist du auf der sicheren Seite. Insbesondere wenn deine Klassen mal komplexer werden, oder du die Strukturen verändern willst und dabei ein Objekt mal gerade nicht seine 4 Byte groß ist, dann geht das Gefrickel los. Nimm dir doch einfach die Zeit und lies ein Buch, bevor du dir aus deinem (C-)Hintergrund heraus schlechten Stil angewöhnst.



  • ok, aber ob ich es mit malloc oder new mache ist doch relativ egal da ich in beiden fällen darauf achten muss, die ressourcen manuell wieder freizugeben.
    wenn ich wegen der operandengrösse nicht sicher bin, kann ich ja sizeof() nehmen.

    ich hab ja malloc nicht ohne triftigen gund angewandt. es ging darum, ein array von n objektreferenzen anzulegen, OHNE die objekte selbst alle auf einmal zu instanzieren. wenn du mir erklärst, wie ich das mit "new" hinkriege, bitte.



  • tenim schrieb:

    ich hab ja malloc nicht ohne triftigen gund angewandt. es ging darum, ein array von n objektreferenzen anzulegen, OHNE die objekte selbst alle auf einmal zu instanzieren. wenn du mir erklärst, wie ich das mit "new" hinkriege, bitte.

    Aber du hast ihn ja sofort danach zugewiesen. Da hättest du auch new nehmen können. Und da das ganze Anwendungscode ist, würde ich das auch in einen Smart Pointer packen. Dann hast du die volle flexibiltät und musst dir keine Sorgen um die Speicherverwaltung machen..

    Und wenn es denn wirklich sein muss, dann würde ich auf vorgefertige Funktionalitäten zurückgreifen und mir einen anständigen Wrapper schreiben und nicht einfach drauflos programmieren..
    http://www.cplusplus.com/reference/std/memory/
    http://www.cplusplus.com/reference/std/new/



  • nein, ich erstell jede objektinstanz mit anderen parametern. deshalb kann ich nicht alles in einem rutsch machen.



  • tenim schrieb:

    nein, ich erstell jede objektinstanz mit anderen parametern. deshalb kann ich nicht alles in einem rutsch machen.

    OK. Das sieht man aber in deinem Beispiel nicht..

    Wie auch immer wäre das alleine für mich noch lange kein Grund malloc oder auch nur new zu benutzen. Ich würde vorher einen Standardcontainer nehmen und da die Elemente pushen und das kannst du für jedes Element andere Parameter übergeben.

    Und wenn ich das aus irgendeinem Grund nicht machen kann/will, dann würde ich sogar vorher einfach die Elemente erzeugen (mit dem Standardkonstruktor) und dann über einen setter die Werte setzen.

    Aber wenn du das unbbedingt mit malloc machen willst..



  • tenim schrieb:

    hey mr. "drakon"

    ich habs in meinem letzten post bereits mit malloc gemacht.
    deine überhebliche art kannst du dir sparen. du bist nicht der einzige, der programmieren kann. ich bin bestimmt kein c++ crack, aber ich machs ja erst seit 2 tagen i n c++.

    Du scheinst ja nicht gerade sehr kritikfähig zu sein. Dravere und drakon haben völlig Recht mit ihren Einwänden.

    Wenn du aus C kommst, kannst du innerhalb von 2 Tagen noch kein C++. Die Konzepte sind grundlegend anders, manuelle Speicherverwaltung kann auf ein Minimum reduziert werden. Das heisst, dass du meistens weder mit malloc() noch mit new hantieren musst, sondern fertige Container der STL anwenden kannst.

    Dann hast du

    std::vector<MyClass> Vec;
    Vec.push_back(MyClass(25, "x25-b77", true));
    

    Das ist doch wohl schöner als jegliches Rumgefrickel mit malloc() .

    • Wie willst du mit malloc() Konstruktoren aufrufen, ohne Placement New einzusetzen?
    • Was, wenn du plötzlich ein Element anhängen willst, und der Speicher nicht mehr reserviert ist?
    • Hast du Kopierkonstruktor und Zuweisungsoperatoren überladen oder wenigstens private gemacht?
    • Rufst du vor dem Freigeben mit free() die Destruktoren auf?
    • Hast du eine separate Variable für die Grösse des dynamischen Arrays, die auch ständig aktualisiert wird?
    • Wie willst du mit malloc() effizient debuggen? Bei den STL-Containern erhält man Assertions.
    • Was ist, wenn du plötzlich merkst, dass ein dynamisches Array doch nicht die richtige Datenstruktur ist und statt dessen eine verkettete Liste angebracht wäre?

    Alle diese Probleme hast du mit STL-Containern nicht. Zudem hast du damit sauberen, übersichtlichen und somit gut wartbaren Code. Die Fehleranfälligkeit und allfällige Memory Leaks fallen praktisch weg.



  • nein, ich komme nicht unbedingt aus der c ecke. hab zwar in c einige zeit programmiert, aber mehr mit java(hab ich auch in einem posting geschrieben, liest halt keiner richtig).

    und kritikfähig bin ich schon, das kannst du mir glauben. nur der ton macht die musik und es ist oft wichtiger, wie jemand etwas sangt, als was er sagt.
    und der umgangston war einfach unhöflich. das erkennen viele leute nicht, weil sie einfach zu tief in ihrer materie drin sind und darauf keinen wert legen.

    ich allerdings schon.



  • tenim schrieb:

    nein, ich komme nicht unbedingt aus der c ecke. hab zwar in c einige zeit programmiert, aber mehr mit java(hab ich auch in einem posting geschrieben, liest halt keiner richtig).

    Hm, während des Threadverlaufs hatte ich irgendwie das Gefühl bekommen, du seist aus C. Wie auch immer, malloc() und free() sind C und haben bis auf einige Ausnahmen nichts in C++ zu suchen (nein, dein Fall ist keine solche Ausnahme).

    tenim schrieb:

    und kritikfähig bin ich schon, das kannst du mir glauben. nur der ton macht die musik und es ist oft wichtiger, wie jemand etwas sangt, als was er sagt.
    und der umgangston war einfach unhöflich. das erkennen viele leute nicht, weil sie einfach zu tief in ihrer materie drin sind und darauf keinen wert legen.

    Es wird auch nicht gerade besonders geschätzt, wenn man als Fragesteller nicht auf die Antworten eingeht. Es wurden viele Vorschläge gebracht, aber du scheinst auf deiner Frickellösung zu beharren. Ich hab zum Beispiel in meinem letzten Post auch versucht, dir die Nachteile vom Rumgefrickel aufzuzeigen. Entweder du glaubst mir, oder ignorierst meinen Post weiterhin. Du musst ja schlussendlich wissen, wie du programmierst. Aber ich wünsche dir jetzt schon mal viel Spass beim Debuggen und Warten...


Anmelden zum Antworten