Operator new[] für abgeleitete Klassen



  • @RudiMBM sagte in Operator new[] für abgeleitete Klassen:

    @DocShoe Und wer bringt nun mich über die Straße?

    Das hat er doch bereits! Das folgende Beispiel von DocShoe finde ich gut.

    Beispiel für statischen Polymorphismus per templates:

    template<typename Calculator>
    ... calculate( ... )
    {
      std::vector<Calculator> calculators( count );
      for( auto& c : calculators ) c.NeueAuswertung(); // kann man sich sparen, wenn >man das bereits im Konstruktor tut
      for( auto& c : calculators ) c.Erstellen( 123 );
      return was_auch_immer;
    }
    
    ... calculate_results( ... )
    {
      if( mode == 1 )       return calculate<C_RechnenMB>( ... );
      else if( mode == 2 )  return calculate<C_RechnenBB>( ... );
      default :             return calculate<C_Rechnen??>( ... );
    }
    


  • @Quiche-Lorraine
    @DocShoe
    Sorry, sowas hab noch nie gebraucht und nie gesehen. Somit verstehe ich (noch) nicht was da abläuft (bis auf vector). Auch hab ich überhaubt keinen Plan wie ich dies in meine Anwendung einbauen könnte.
    Ich verstehe auch nicht warum meine Version mit einem Array von Klassen nicht funktioniert. In der Vorgängerversion hab ich die KlassenPtr genauso verwendet und der Ptr auf die Basiklasse hat auch funktioniert, nur habe ich alle Instanzen einzeln nacheinander erzeugt und wieder deleted. Und das scheint mir auch logisch im Classenkonzept. Denn wenn ich zB "Shape->Draw();" programmiere, dann benutze ich ja auch den Basisptr der Shapeklasse.



  • @RudiMBM sagte in Operator new[] für abgeleitete Klassen:

    Sorry, sowas hab noch nie gebraucht und nie gesehen. Somit verstehe ich (noch) nicht was da abläuft (bis auf vector). Auch hab ich überhaubt keinen Plan wie ich dies in meine Anwendung einbauen könnte.

    Dann wird es Zeit dass du ein Testprojekt generierst und dich intensiv mit der STL und Templates beschäftigst.


    Dein Code erscheint mir insgesammt zu C lastig. Alleine von der folgenden Zeile stellen sich schon meine Nackenhaare.

    void* operator new[]( size_t C_RechnenMB ) { return malloc( C_RechnenMB ); };
    

    So einen Code ist höchst fehleranfällig und ist in C++ nur noch selten notwendig.



  • @RudiMBM sagte in Operator new[] für abgeleitete Klassen:

    Ich verstehe auch nicht warum meine Version mit einem Array von Klassen nicht funktioniert. In der Vorgängerversion hab ich die KlassenPtr genauso verwendet und der Ptr auf die Basiklasse hat auch funktioniert, nur habe ich alle Instanzen einzeln nacheinander erzeugt und wieder deleted. Und das scheint mir auch logisch im Classenkonzept. Denn wenn ich zB "Shape->Draw();" programmiere, dann benutze ich ja auch den Basisptr der Shapeklasse.

    Das haben TH69 und ich doch schon ausführlich erklärt. Der nicht-Pointer Ansatz kann nicht funktionieren, da du einen Zeiger der Basisklasse auf das erste Arrayelement zeigen lässt und der der Zeiger bei der Inkrementierung halt nur um die Größe der Basisklasse verschoben wird, und wenn die abgeleitete Klasse größer als die Basisklasse ist, dann steht dein Zeiger iwo im Speicher.
    Wenn du alle Objekte separat auf dem Heap erzeugst hast du ein Array aus Zeigern. Zeiger sind immer gleich groß, egal, auf was sie zeigen, daher funktioniert die Zeigerarithmetik.



  • @Quiche-Lorraine sagte in Operator new[] für abgeleitete Klassen:
    ...

    Blödsinn gelöscht



  • @RudiMBM
    Du kannst deinen Speicher selber allozieren und verwalten, wenn du unbedingt möchtest, sollte man aber vermeiden und ist in C++ so nicht mehr nötig. Selbst in "altem" C++ sollte man das wegkapseln (Stichwort RAII).

    Warum iterierst du über den ErgAnz Pointer? Warum nicht von 0 - Anzahl

    for(unsigned int i = 0; i<Anzahl; ++i)
    {
       ErgAnz[i].NeueAuswertung();
    }
    


  • @DocShoe ist klar. Nur wenn ich die Objekte einzeln Erzeuge, kann ich mir nicht sicher sein, dass sie ohne Lücken im Heap stehen. Evtl. wollte ich das ganze array auf Platte stremen.



  • @Schlangenmensch Macht den gleichen Fehler wie Ptr++,, das hatte ich schon vorher probiert.



  • @RudiMBM sagte in Operator new[] für abgeleitete Klassen:

    @DocShoe ist klar. Nur wenn ich die Objekte einzeln Erzeuge, kann ich mir nicht sicher sein, dass sie ohne Lücken im Heap stehen. Evtl. wollte ich das ganze array auf Platte stremen.

    Das dürfte aus den gleichen Gründen wie oben sowieso nicht funktionieren. Mit der Zuweisung C_Rechnen* ErgAnzArray = new C_RechnenMB[100] verlierst du sämtliche Informationen über den konkreten Datentyp! D.h., du kannst nicht mal mehr bestimmen, wie groß das Array im Speicher wirklich ist (gemessen in Bytes). Und damit können auch so Sachen wie fwrite( ErgAnzArray, Elementgröße?, anzahl, handle ) nicht funktionieren. Abgesehen davon, dass das so oder so kein gutes I/O Datenhandling ist.

    Du verrennst dich da in etwas, das definitiv in einer Sackgasse endet.



  • @DocShoe Öhm... stimmt natürlich. Zu wenig Kaffee.



  • @DocShoe Sehr ermundernt. Zum Glück habe ich ne hohe Resilientz.



  • @RudiMBM sagte in Operator new[] für abgeleitete Klassen:

    @DocShoe Sehr ermundernt. Zum Glück habe ich ne hohe Resilientz.

    Was erwartest du? Du fragst, weil du nicht weiterkommst. Quasi alle Antworten sagen dir, dass du auf dem Holzweg bist.
    Und statt die Ratschläge zu beherzigen beharrst du auf deinem Ansatz.

    Na dann... viel Erfolg!



  • @DocShoe
    Ich sagte oben: Sorry, sowas hab noch nie gebraucht und nie gesehen. Somit verstehe ich (noch) nicht was da abläuft (bis auf vector). Auch hab ich überhaubt keinen Plan wie ich dies in meine Anwendung einbauen könnte.
    Das kommt nicht von Wollen, sondert ist vom Können behindert.



  • Wenn es denn so formuliert sein soll. Smart Pointer sind sehr sinnvoll! Kann man das ganze so ohne operator new[] formulieren.

    P.S. Es wäre schön gewesen, wenn Du ein übersetzbares Stück Code hier reingestellt hättest.

    #include <stdexcept>
    
    class C_Rechnen {
    public:
    	C_Rechnen() = default;
    
    	virtual ~C_Rechnen() = 0;
    	virtual void NeueAuswertung() = 0;
    	virtual	void Erstellen(int) = 0;
    	virtual void TestIter() = 0;
    
    	long double	innermax, innermin, outermax, outermin;
    	long int	ax, ay;
    	int			itercount;
    };
    
    C_Rechnen::~C_Rechnen() {}
    
    
    class C_RechnenMB : public C_Rechnen {
    public:
    	C_RechnenMB() = default; 
    	~C_RechnenMB() {};
    
    	static C_Rechnen* generate(size_t number) {
    		if (0 == number) throw std::runtime_error ("Anzahl muss größer als 0 sein.");
    		return new C_RechnenMB[number];
    	}
    
    	void NeueAuswertung() {};
    	void Erstellen(int) {};
    	void TestIter() {};
    };
    
    
    class C_RechnenBB : public C_Rechnen {
    public:
    	C_RechnenBB() = default;
    	~C_RechnenBB() {};
    
    	static C_RechnenBB* generate(size_t number) {
    		if (0 == number) throw std::runtime_error ("Anzahl muss größer als 0 sein.");
    		return new C_RechnenBB[number];
    	}
    
    	void NeueAuswertung() {};
    	void Erstellen(int) {};
    	void TestIter() {};
    };
    
    class C_RechnenXX: public C_Rechnen {
    public:
    	C_RechnenXX() = default;
    	~C_RechnenXX() {};
    
    	static C_RechnenXX* generate(size_t number) {
    		if (0 == number) throw std::runtime_error ("Anzahl muss größer als 0 sein.");
    		return new C_RechnenXX[number];
    	}
    
    	void NeueAuswertung() {};
    	void Erstellen(int) {};
    	void TestIter() {};
    };
    
    int main () {
    	int Mode = 1;
    	size_t Anzahl = 10;
    
    	C_Rechnen* ErgAnzArray = nullptr;
    
    	switch (Mode) {
    		case 1:
    			ErgAnzArray = C_RechnenMB::generate(Anzahl); break;
    		case 2:
    			ErgAnzArray = C_RechnenBB::generate(Anzahl); break;
    		default:
    			ErgAnzArray = C_RechnenXX::generate(Anzahl); break;
    	}
    }
    


  • @john-0 Danke, da hast du dir aber viel Mühe gemacht. Mir scheint, das ist die Umsetzung von DocShoe. Dieser Code ist doch übersichtlich. Ich werde ihn gleich mal einbauen.
    Bis dann...
    Gruß Rudi



  • Das löst das Problem doch nicht. Du hast wieder einen Zeiger auf die Basisklasse, mit dem man praktisch nichts anfangen kann.



  • Es fehlt der restliche Code um zu sehen, was er wirklich will.



  • @john-0 Sorry, DocShoe hatte recht. Alles wie von Anfang an falsch.
    Ich lern mal RAII: Weiß jemand ob C++Builder 2009 schon mit C++11 compiliert? Ansonsten kann ich mir das sparen.



  • @RudiMBM

    Ne, der C++ Builder 2009 kann kein C++11, und auch mit templates hat der so seine Probleme. Ist halt noch der alte, verbuggte bcc32 Compiler. Aber RAII funktioniert auch ohne C++11, das ist ein Konzept, und kein Sprachfeature.
    Ohne C++11 hast du leider keine vernünftigen smart_ptr. Ich habe damals für das RAD Studio 2007 die boost Bibliotheken selbst übersetzt, das war nicht trivial, und nur für boost::shared_ptr würde ich das nicht versuchen.
    Aber als Programmieraufgabe kannst du dir ja die Implementierung einer eigenen shared_ptr Klasse setzen, wenn man so Sachen wie thread safety, weak_ptr und custom deleter weglässt ist das nicht so schwierig und mit 50-100 Zeilen Code zu machen.



  • Danke an alle für die Ratschläge.
    Ich glaube nun ist an der Zeit meinen alten launenhaften C++Builder zu verschrotten. Weil der neue auch nichts taugt, wende ich mich nun Linux und Phyton zu. Hier gibts noch Aufbruchslaune. Obwohl ich schon 1980 mit einem UNIX-Mainframe und 1990 mit Unix-Sun-Sparc rummachte, konnte ich mich noch nicht für Linux entscheiden. Damals war Windows soweit wie Linux erst vor ~5 Jahren. Jetzt erscheint mir das Ende der Fahnenstange erreicht und fang nochmal an.
    Glück auf, und sonstige Grüße.
    Rudi


Anmelden zum Antworten