Operator new[] für abgeleitete Klassen
-
@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 wiefwrite( 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.
-
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
-
@RudiMBM sagte in Operator new[] für abgeleitete Klassen:
Weil der neue auch nichts taugt, wende ich mich nun Linux und Phyton zu.
Python ist aber leider nicht für seine Schnelligkeit bekannt. Denkbar das du zu deinem Problem ein Performanceproblem bekommt.
Warum nutzt du nicht einen neuere Compiler ala GCC der von Compiler von Visual Studio?
-
Bevor ihr über potentielle Geschwindigkeitsprobleme sinniert: ich verstehe nicht, warum @RudiMBM nicht einfach erstmal einen
vector<BaseClass*>
nimmt. Meinetwegen auch mit owning raw ptr, wenn der Compiler kein C++11 kann. Das wird in >99% der Fälle schon nicht zu langsam sein.
-
@DocShoe sagte in Operator new[] für abgeleitete Klassen:
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.
Unter UNIX ging das ganze sehr gut mit C++98 Compiler (GCC und MIPSPro). Für einen shared_ptr braucht es kein C++11, für unqiue_ptr ist C++11 oder neuer hingegen Pflicht.
@RudiMBM sagte in Operator new[] für abgeleitete Klassen:
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.UNIX lief traditionell nicht auf Mainframes sondern auf Minicomputern. Mittlerweile kann man auf IBMs zSeries z/Linux betreiben, aber nicht IBMs eigenes UNIX AIX. Das läuft nur auf der Power Hardware, die die konsolidierte gemeinsame Plattform für IBMs UNIX AIX und dem Nachfolger des Mini Computer OS der AS/400 sind, und natürlich läuft darauf auch Linux für Power. IMHO ist BS2000 die einzige nicht IBM Mainframe Plattform, die bis heute überlebt hat.
Unter Linux gibt es ein Sammelsurium von freien bzw. frei verfügbaren C und C++ Compilern: GCC, clang, Intel, nVidia (vormals PGI), AMD, … Bei Deinen Problembeschreibungen erscheint mir NumPy eine sinnvoller Einstieg zu sein, wenn Du denn wechseln willst. Mein Rat wäre zuerst einen freien neueren C++ Compiler unter Windows zu probieren. Ein Wechsel zieht so einiges nach sich, so dass es da nicht nur ums Programmieren geht.
-
Jups, deswegen schrub ich auch
shared_ptr
. Ohne Move-Semantik keinunique_ptr
. Und es gibt zwei große Probleme, wenn man mit dem RAD Studio/Builder arbeitet:- der bcc32 C++ Compiler, der nicht mal zu sich selbst kompatibel ist. Ok, das ist übertrieben, aber die ganze Toolchain hat schon ordentliche Macken.
- die Visual Component Framework (VCL). Grafische Komponenten in Delphi, die sich mit dem C++ Builder nutzen lassen. Wird von keinem anderen C++ Compiler unterstützt. D.h., wenn man sich vom C++ Builder trennt, dann trennt man sich auch von seinem GUI. Andererseits ist der bcc32 Compiler auch so schlecht, dass sich Open Source Frameworks nicht damit übersetzen lassen.
-
Hallo, hier noch einen Nachtrag.....
Meine Idee war einen ClassPointer zu haben, mit dem ich in der gesamten Anwendung zugriff auf die ausgewählte Subklasse C_RechenXX habe.
Das kann natürlich nur ein Ptr auf die Basisklasse sein. Soweit funktioniert das.
Damit aber handele ich mir die Nachteile ein:- Kein direkter Zugriff auf public Eigenschaften der Subklassen.
- Alle public Subklassen-Methoden müßen abgeleitete sein.
- Zeigerarithmetik des Pointers bezieht sich immer auf die Size der Basisklasse. Sowas geht schwer in die Hose und war auch mein ursprüngliches Problem.
Warum kann ich das trotzdem anwenden?:
- Meine Subklassen haben keine public Eigenschaften
- Ist eh so.
- Die Zeigerarithmetik mußte ich mir selber basteln, war aber erstaunlich leicht.
Also, das Programm läuft, auch wenn es so nicht "State of the Art" ist
Nun sieht es so aus.:
class C_Rechnen { public: C_Rechnen() ; ~C_Rechnen(); virtual void NeueAuswertung() = 0; virtual void Erstellen(int) = 0; virtual C_Rechnen* Next() = 0; virtual C_Rechnen* ArrPos( int ) = 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(); ~C_RechnenMB() {}; C_Rechnen* Next() { __int8 *aa = (__int8*)this; aa += sizeof(C_RechnenMB); return (C_Rechen*)aa; } C_Rechnen* ArrPos( int ix) { __int8 *aa = (__int8*)this; aa += sizeof(C_RechnenMB) * ix; return (C_Rechen*)aa; } void NeueAuswertung() {}; void Erstellen(int) {}; }; class C_RechnenBB : public C_Rechnen { public: C_RechnenBB(); ~C_RechnenBB() {}; C_Rechnen* Next() { __int8 *aa = (__int8*)this; aa += sizeof(C_RechnenBB); return (C_Rechen*)aa; } C_Rechnen* ArrPos( int ix) { __int8 *aa = (__int8*)this; aa += sizeof(C_RechnenBB) * ix; return (C_Rechen*)aa; } void NeueAuswertung() {}; void Erstellen(int) {}; int BBdaten; // Kein zugriff mit BasisPtr, wird aber bei sizeof(C_RechnenBB) mitgezählt. }; int main () { int Mode = 1; size_t Anzahl = 10; C_Rechnen *ErgAnzArray, *ErgAnz; switch (Mode) { case 1: ErgAnzArray = new C_RechnenMB[Anzahl]; break; case 2: ErgAnzArray = new C_RechnenBB[Anzahl]; break; default ErgAnzArray = new C_RechnenXX[Anzahl]; break; } } ErgAnz = ErgAnzArray; for ( ................) { ErgAnz->ax = 656565; ErgAnz->Erstellen(); ErgAnz = ErgAnz->Next(); } ........ ErgAnz = ErgAnzArray->ArrPos( nth-Element ); // entspricht ErgAnz[ nth-Element ]
Ist ne' Hauruck-Methode, aber läuft!
Gruß Rudi
-
Sowas hab ich doch vor Tagen schon gepostet, nur in typsicher:
class C_Rechnen { virtual C_Rechnen* advance( C_Rechnen* current ) const = 0; }; class C_RechnenMB { C_Rechnen* advance( C_Rechnen* current ) const override { // Pointer wird um die Größe der konkreten Klasse verschoben C_RechnenMB* tmp = dynamic_cast<C_RechnenMB*>( current ); return tmp ? ++tmp : nullptr; } } // Pointer auf nächstes Element wird durch das Element selbst bestimmt. C_Rechnen* arr = new C_RechnenMB[2]; arr = arr->advance( arr );
-
@DocShoe pow! bis du schnell.
-
Zwei Monitore und ein großes Projekt zu übersetzen