Guten Abend,
ich bin noch am Anfang meiner C++-Gehversuche, aber beim Sichten aller
Array-ähnlichen Konstrukte, die ich in meinem Buch und auf
https://en.cppreference.com bislang gesichtet habe, scheint es nur
"arrays" gleicher Klassen zu geben.
Angenommen, ich hätte eine Gruppe von abgeleiteten Klassen einer
Basisklasse, die alle die gleiche Methode (z.B. disp()) besitzen - gibt
es eine Möglichkeit, diese in eine Art array zu packen und mit einer
for-Schleife darüberzuiterieren?
Kann mir jemand das passende Stichwort geben?
Du kannst zB Objekte von Typ LKW, Motorrad, Fahrrad und PKW haben, die
alle von "Fahrzeug" abgeleitet sind.
Die kannst du dann in ein Array von Fahrzeugen speichern und kannst die
Methode fahren() aufrufen, falls diese Methode in Fahrzeug definiert
ist.
Gähn schrieb:> Die kannst du dann in ein Array von Fahrzeugen
Wenn ich die Objekte aus "Motorrad", "Auto" etc. in ein Array mit
"Fahrzeug" packe - gehen nicht die zusätzlichen Attribute von "Motorrad"
verloren? Wird dann nicht die Methode Auto::fahren() anstelle
Motorrad::fahren() aufgerufen (oder geht schief, wenn Auto::fahren() nur
eine virtuelle Funktion ist?)
Walter T. schrieb:> Gähn schrieb:>> Die kannst du dann in ein Array von Fahrzeugen>> Wenn ich die Objekte aus "Motorrad", "Auto" etc. in ein Array mit> "Fahrzeug" packe - gehen nicht die zusätzlichen Attribute von "Motorrad"> verloren? Wird dann nicht die Methode Auto::fahren() anstelle> Motorrad::fahren() aufgerufen (oder geht schief, wenn Auto::fahren() mir> eine virtuelle Funktion ist?
Richtig, das ist mal wieder absoluter Blödsinn was hier geschrieben
wird.
Danke, das heisst, prinzipiell ist es möglich. Dann habe ich mit
unique_ptr und "iterator" ja erst einmal wieder den passenden Lesestoff.
Um ehrlich zu sein, ist die Aussicht, über eine Liste unterschiedlicher
Objekte iterieren zu können, überhaupt erst der Grund, mit C++
angefangen zu haben.
Könnt ihr mir noch verraten, ob es prinzipiell möglich ist, diese Liste
komplett im Flash eines Mikrocontrollers zu halten? (Auf Anhieb sehe ich
da kein ernsthaftes Hindernis, aber ich kenne die Möglichkeiten der
Sprache noch nicht.)
Walter T. schrieb:> Um ehrlich zu sein, ist die Aussicht, über eine Liste unterschiedlicher> Objekte iterieren zu können, überhaupt erst der Grund, mit C++> angefangen zu haben.
1) das wäre auch in jeder anderen OOP-Sprache möglich. Du kannst immer
Objekte iterieren, die eine gemeinsame Basisklasse haben und die in
einem Konstrukt stecken, über das man iterieren kann.
2) man kann das auch in Nicht-OOP-Sprachen realisieren. Man muss halt
nur das OOP-Feature "Polymorphie" mit den Mitteln dieser Sprache
abbilden. Für C würde das beispielweise bedeuten: Iteriert wird z.B.
über ein Array von Strukturen und diese Strukturen enthalten
Funktionszeiger für all den Scheiß, der bei C++ als virtuelle Methoden
auftaucht.
Der Witz ist: viel weniger schick als in C++ wird es auch in C nicht.
Jedenfalls sobald man für ein spezielles Objekt im Zuge der Iteration
dann doch das braucht, was nicht schon in der gemeinsamen Basisklasse
als virtuelle Methode existiert. Dann sieht das in C++ schon wieder fast
genauso aufwendig aus, wie in C...
Walter T. schrieb:> Danke, das heisst, prinzipiell ist es möglich. Dann habe ich mit> unique_ptr und "iterator" ja erst einmal wieder den passenden Lesestoff.>> Um ehrlich zu sein, ist die Aussicht, über eine Liste unterschiedlicher> Objekte iterieren zu können, überhaupt erst der Grund, mit C++> angefangen zu haben.>> Könnt ihr mir noch verraten, ob es prinzipiell möglich ist, diese Liste> komplett im Flash eines Mikrocontrollers zu halten? (Auf Anhieb sehe ich> da kein ernsthaftes Hindernis, aber ich kenne die Möglichkeiten der> Sprache noch nicht.)
Code landet "immer" in der .text Section eines Mikrocontrollers und
damit im Flash. Egal von welcher Programmiersprache der kommt.
Ich glaub du würdest gerne andere Fragen stellen, bist aber noch nicht
weit genug um diese formulieren zu können. Du musst glaub ich erst
einmal verstehen was Polymorphie im Prinzip ist, welche Arten es davon
gibt und wie diese in C++ repräsentiert werden können.
Walter T. schrieb:> Könnt ihr mir noch verraten, ob es prinzipiell möglich ist, diese Liste> komplett im Flash eines Mikrocontrollers zu halten?
Die Liste der Obejkte ist nur eine Liste von Zeigern (auch wenn die
möglicherweise Referenzen heißen: im Kern sind's doch nur dämliche
Zeiger).
Das Problem ist eher, dass die Objekte selber Speicherplatz im RAM
benötigen. Und virtuelle Methoden tragen hier sogar ziemlich dick auf...
c-hater schrieb:> 2) man kann das auch in Nicht-OOP-Sprachen realisieren. Man muss halt> nur das OOP-Feature "Polymorphie" mit den Mitteln dieser Sprache> abbilden. Für C würde das beispielweise bedeuten: Iteriert wird z.B.> über ein Array von Strukturen und diese Strukturen enthalten> Funktionszeiger für all den Scheiß, der bei C++ als virtuelle Methoden> auftaucht.
Ja, habe ich momentan. Das ist häßlich, und die Definition ist extrem
fehleranfällig. (Entweder Identifikation des Datentyps über enum und
Aufruf der ausführenden Funktion über switch/case oder eben über
Funktionszeiger direkt im Array oder beides.) Da erhoffe ich mir über
templates + virtual functions eine erhebliche Vereinfachung.
Vincent H. schrieb:> Code landet "immer" in der .text Section eines Mikrocontrollers und> damit im Flash. Egal von welcher Programmiersprache der kommt.> [...]> Ich glaub du würdest gerne andere Fragen stellen, bist aber noch nicht> weit genug um diese formulieren zu können.
Ich meine nicht den Code, sondern das array. Wenn aus dem array ein
Element im RAM landet, kann ich damit leben. Wenn das komplette array
ins RAM geladen wird, bin ich am Ende.
c-hater schrieb:> Das Problem ist eher, dass die Objekte selber Speicherplatz im RAM> benötigen. Und virtuelle Methoden tragen hier sogar ziemlich dick auf...
Das heisst, konstante Objekte werden vor dem Lesen von Attributen
grundsätzlich ins RAM kopiert? Oder vor dem Ausführen einer Methode?
Oder wird nur der vtable ins RAM kopiert?
Nicht, dass das schlimm wäre... damit kann ich leben. Nur nicht mit
allen gleichzeitig.
c-hater schrieb:> Das Problem ist eher, dass die Objekte selber Speicherplatz im RAM> benötigen. Und virtuelle Methoden tragen hier sogar ziemlich dick auf...
VTables brauchen keinen RAM. (außer wohl beim AVR?)
Walter T. schrieb:> Das heisst, konstante Objekte werden vor dem Lesen von Attributen> grundsätzlich ins RAM kopiert? Oder vor dem Ausführen einer virtuellen> Funktion?
Es ist eigentlich ganz simpel. C++ tut was C tut.
Virtuelle Funktionen haben nichts mit dem RAM Verbrauch zu tun.
Vincent H. schrieb:> Walter T. schrieb:>> Gähn schrieb:>>> Die kannst du dann in ein Array von Fahrzeugen>>>> Wenn ich die Objekte aus "Motorrad", "Auto" etc. in ein Array mit>> "Fahrzeug" packe - gehen nicht die zusätzlichen Attribute von "Motorrad">> verloren? Wird dann nicht die Methode Auto::fahren() anstelle>> Motorrad::fahren() aufgerufen (oder geht schief, wenn Auto::fahren() mir>> eine virtuelle Funktion ist?>> Richtig, das ist mal wieder absoluter Blödsinn was hier geschrieben> wird.
Wieso denn Blödsinn? Selbstverständlich ist es möglich, es so zu machen
wie von Gähn beschrieben. Hier der Beweis: Code im Anhang und die
Ausgabe siehe unten.
Vincent H. schrieb:> c-hater schrieb:>> Das Problem ist eher, dass die Objekte selber Speicherplatz im RAM>> benötigen. Und virtuelle Methoden tragen hier sogar ziemlich dick auf...>> VTables brauchen keinen RAM. (außer wohl beim AVR?)>> Walter T. schrieb:>> Das heisst, konstante Objekte werden vor dem Lesen von Attributen>> grundsätzlich ins RAM kopiert? Oder vor dem Ausführen einer virtuellen>> Funktion?>> Es ist eigentlich ganz simpel. C++ tut was C tut.> Virtuelle Funktionen haben nichts mit dem RAM Verbrauch zu tun.
Natürlich brauchen vtables RAM. Selbst wenn du sie in C selber bastelst,
brauchen sie RAM (function pointer). Die Information welcher Art ein
Objekt ist, muss zur Laufzeit/dynamisch vorliegen. So funktioniert
dynamic_cast und RTTI und deshalb hat es auch entsprechenden overhead.
DU kannst deine Klasse auch gnu::packed machen und dann sizeof(...)
vergleichen.
https://en.wikipedia.org/wiki/Virtual_method_table#cite_note-4https://en.cppreference.com/w/cpp/language/virtual
Walter T. schrieb:> Das heisst, konstante Objekte werden vor dem Lesen von Attributen> grundsätzlich ins RAM kopiert? Oder vor dem Ausführen einer Methode?> Oder wird nur der vtable ins RAM kopiert?
Das kommt drauf an. Es gibt dafür keine Notwendigkeit, aber je nach
Compiler und Architektur wird es ggf. trotzdem gemacht.
Vincent H. schrieb:> c-hater schrieb:>> Das Problem ist eher, dass die Objekte selber Speicherplatz im RAM>> benötigen. Und virtuelle Methoden tragen hier sogar ziemlich dick auf...>> VTables brauchen keinen RAM. (außer wohl beim AVR?)
Sofern sich da nichts geändert hat, kopiert AVR-GCC beim Start alle
vtables in den RAM. Das liegt aber im Wesentlichen daran, dass beim AVR
RAM und Flash unterschiedlich angesprochen werden müssen und das im
Compiler so nicht vorgesehen ist.
Mark B. schrieb:> Wieso denn Blödsinn? Selbstverständlich ist es möglich, es so zu machen> wie von Gähn beschrieben.
Nur arbeitet dein Code halt nicht so wie beschrieben. Er speichert keine
Fahrzeuge im vector, sondern Zeiger.
C++ Kenner schrieb:>> Es ist eigentlich ganz simpel. C++ tut was C tut.>> Virtuelle Funktionen haben nichts mit dem RAM Verbrauch zu tun.>> Natürlich brauchen vtables RAM.
Sie brauchen Speicher. Ob das RAM sein muss, hängt nur von den
Limitierungen des Compilers ab.
> Selbst wenn du sie in C selber bastelst, brauchen sie RAM (function> pointer).
Nein. vtables ändern sich zur Laufzeit nicht. Und bei Objekten, die
komplett konstant sind, spricht auch nichts dagegen, dass der
vtable-Pointer das auch ist. In dem Fall wird exakt 0 RAM dafür
benötigt.
> Die Information welcher Art ein Objekt ist, muss zur Laufzeit/dynamisch> vorliegen.
Nur wenn das Objekt zur Laufzeit dynamisch erzeugt wurde. Und auch dann
ist es nur der vtable-Pointer, nicht die ganze vtable, die im RAM stehen
muss.
C++ Kenner schrieb:> Wer statische Polymorphie möchte, nimmt std::variant und z.B.> std::visit.
std::variant ist, auch wenn es beim dispatch via std::visit so aussieht,
eigentlich keine statische Polymorphie.
Danke für Deinen Beitrag! Es ist nicht ganz, was ich suche *), aber
trotzdem interessant.
Mark B. schrieb:> Hier der Beweis: Code im Anhang
Dieser Teil hier:
Es läuft also implizit ein static cast auf einen Zeiger auf einen Objekt
der Klasse Fahrzeug, wenn das Zeiger-Array erzeugt wird. Wieso wird ein
Zeiger, der auf ein Objekt der Klasse Fahrzeug zeigt, als Objekt der
Klasse Motorrad dereferenziert?
*) letztendlich will ich am Ende eine Konstante mit tabellenartiger
Initializer-Liste. Wenn ich tausend konstante Variablen mit Zeigern
drauf erzeugen muss, wird es noch unübersichtlicher als sowieso schon.
Aber ich gehe mal davon aus, dass das irgendwie --wie auch bei einem
cstring-Array-- geht.
Walter T. schrieb:> Wieso wird ein> Zeiger, der auf ein Objekt der Klasse Fahrzeug zeigt, als Objekt der> Klasse Motorrad dereferenziert?
Wird es nicht. Lediglich beim Aufruf von virtuellen Funktionen wird beim
Aufruf eben die Funktion der abgeleiteten Klasse aufgerufen. Sie muss
dazu aber auch in der Basisklasse deklariert sein.
Walter T. schrieb:> *) letztendlich will ich am Ende eine Konstante mit tabellenartiger> Initializer-Liste.
Führ das doch mal genauer aus. Vielleicht kann man eine bessere
Möglichkeit finden.
Programmierer schrieb:> Führ das doch mal genauer aus. Vielleicht kann man eine bessere> Möglichkeit finden.
In Pseudocode will ich irgendwann einmal etwas wie das hier
implementiert haben:
Sprich: große, konstate Arrays mit gemischten Typen und darüber
iterieren können.
Aber ich suche die Lösung noch gar nicht jetzt. Ich bin bei meinem
C++-Buch erst bei Seite 135. Der Zweck des Threads war nur, abschätzen
zu können, ob ich hier überhaupt in die richtige Richtungs ziele (und
nach Seite 1007 die Lösung finden können werde).
Sprich: Ob es für mein aktuelles Problem sinnvoller ist, C++ zu lernen,
oder meine Zeit lieber darin zu investieren, einen Codegenerator für C
zu schreiben.
Walter T. schrieb:> Könnt ihr mir noch verraten, ob es prinzipiell möglich ist, diese Liste> komplett im Flash eines Mikrocontrollers zu halten? (Auf Anhieb sehe ich> da kein ernsthaftes Hindernis, aber ich kenne die Möglichkeiten der> Sprache noch nicht.)
falls es das deine Frage ist - man kann die Objekte auch nur auf dem
Stack, oder global anlegen - falls deinen Objekte nicht auf dem Heap
liegen müssen
Walter T. schrieb:> Sprich: große, konstate Arrays mit gemischten Typen und darüber> iterieren können.
Das Problem ist, dass die unterschiedlichen Typen unterschiedlich groß
sind, und daher nicht in ein Array gepackt werden können, denn wie soll
die Adresse von Element X berechnet werden, wenn nicht mit X*sizeof(T) ?
Daher der Trick, dass im Array nur der Zeiger steht, denn alle Zeiger
sind gleich groß. Das impliziert aber, dass die eigentlichen Objekte
noch irgendwo anders abgelegt sind, wo der Zeiger dann hin zeigt. Auf
dem Heap anlegen via "new" geht zwar, ist aber für Mikrocontroller
ineffizient, und wenn die ganze Struktur sowieso fix ist, auch unnötig.
Am Logischsten wäre es, vor "MainScreen" alle Objekte einmal manuell zu
definieren, und im Array dann Pointer darauf anzulegen. Das wäre
allerdings eine Menge Boilerplate-Code.
Daher habe ich mal aus Spaß im Anhang eine Klasse PolymorphicContainer
implementiert, welche die Objekt-Instanzen in einem Tupel ablegt, und in
einem Array die Pointer darauf. Damit kann man den Code fast genau so
hinbekommen wie du ihn haben wolltest:
Die designated Initializer erfordern C++20. So kannst du das Array
iterieren und virtuelle Funktionen wie gehabt nutzen. Falls gewünscht
kannst du per "std::get<0> (MainScreen.tuple)" o.ä. direkt auf bestimmte
Elemente zugreifen und erhältst dann auch den konkreten Typ, allerdings
muss der Index fix und dem Compiler bekannt sein.
Zum "Vergleich" habe ich noch die Funktion "staticIteration"
mitgeliefert, mit der man durch das Tupel iterieren kann, ohne den Umweg
über das Array und Zeiger:
Die Variable "elem" hat dabei immer den konkreten Typ, somit kann man
auf die spezifischen Elemente der abgeleiteten Klasse zugreifen. Somit
werden hier keine virtuellen Funktionen gebraucht. Allerdings wird hier
keine Schleife erzeugt, sondern es wird für jedes Element im Tupel
Code für den Aufruf generiert. Dadurch kann der Code sehr schnell sehr
groß werden, was dann nicht unbedingt geeignet ist.
Walter T. schrieb:> Die Frage ist: Kann ich ein globales Array mit anonymen Variablen> anlegen, wenn diese einen unterschiedlichen Typ haben?
du hast mindestens 4 Antworten dazu
Programmierer schrieb:> Daher habe ich mal aus Spaß im Anhang eine Klasse PolymorphicContainer> implementiert,
Die 100 Punkte für maximale Anfängerverwirrung gehen definitiv an dich
:)
@Walter T.
einfach ignorieren :)
Die Frage ist ungenau gestellt. Was sind "anonyme Variablen"?
Ein Array kann nur Elemente von selben Typ speichern, das ist in C++
nicht anders als in C. Der Typ kann aber, wie oben in den Beispielen,
ein Pointer oder eine Referenz auf eine Basisklasse sein, während die
dazugehörigen Instanzen abgeleitete Klassen der Basisklasse sind.
Oliver
Programmierer schrieb:> [...]
Danke, dafür werde ich mir wohl noch etwas Zeit nehmen müssen, bis ich
das verstehe.
Programmierer schrieb:> Das Problem ist, dass die unterschiedlichen Typen unterschiedlich groß> sind, und daher nicht in ein Array gepackt werden können, denn wie soll> die Adresse von Element X berechnet werden, wenn nicht mit X*sizeof(T) ?Oliver S. schrieb:> Die Frage ist ungenau gestellt. Was sind "anonyme Variablen"?
Meinem Verständnis nach analoges Beispiel in C:
List ist ein Pointer Array auf anonyme Variablen gleichen Typs
unterschiedlicher Größe, lässt sich aber in einem Rutsch hinschreiben.
In C ein Beispiel mit einem Pointer Array auf anonyme Variablen
unterschiedlichen Typs, das sich in einem Rutsch hinschreiben lässt, und
mit dem man auch noch etwas anfangen kann, bekomme ich gerade nicht hin.
Walter T. schrieb:> Meinem Verständnis nach analoges Beispiel in C:
String-Literale sind ein Sonderfall, weil deren Lebenszeit von C/C++
automatisch global gemanagt wird.
Walter T. schrieb:> In C ein Beispiel mit einem Pointer Array auf anonyme Variablen> unterschiedlichen Typs, dass sich in einem Rutsch hinschreiben lässt,> bekomme ich gerade nicht hin.
Auch mit gleichem Typ geht es nicht, außer bei String-Literalen... Du
musst die Variablen irgendwo hin ablegen. Meine
PolymorphicContainer-Klasse vereinfacht das. Mehrfach malloc/new nutzen
geht natürlich auch, aber das ist für solche Konstrukte eben Overhead.
Walter T. schrieb:> Danke, dafür werde ich mir wohl noch etwas Zeit nehmen müssen, bis ich> das verstehe.
Du kannst die Klasse auch so verwenden wie sie ist ohne die Details zu
verstehen, ist ja bei Nutzung von std::vector etc auch nicht anders,
dessen Innereien sind auch schwer verdaulich. Die Verwendung ist ja am
Beispiel ersichtlich.
Walter T. schrieb:> Die Frage ist: Kann ich ein globales Array mit anonymen Variablen> anlegen, wenn diese einen unterschiedlichen Typ haben?
Nein, siehe oben.
Du kannst aber einen heterogenen Container anlegen.
Sehr ich das richtig, dass ich über ein tuple nicht in einer
for-Schleife mit einer Auto-Variable drüberiterieren kann, und bei der
Initialisierung an zwei Stellen (in der Deklaration und in der
Initializer List) Buch führen muss, um welchen Datentyp es sich handelt?
Das würde es für eine Liste mit > 100 Einträgen eigentlich schon direkt
disqualifizieren.
Irgendwie fürchte ich gerade, dass ich so oder so um einen Codegenerator
nicht herumkomme.
Walter T. schrieb:> Sehr ich das richtig, dass ich über ein tuple nicht in einer> for-Schleife mit einer Auto-Variable drüberiterieren kann
Richtig.
Walter T. schrieb:> und bei der> Initialisierung an zwei Stellen (in der Deklaration und in der> Initializer List) Buch führen muss, um welchen Datentyp es sich handelt?
Auch richtig. Daher macht man schlauerweise beides in einem.
Walter T. schrieb:> Das würde es für eine Liste mit > 100 Einträgen eigentlich schon direkt> disqualifizieren.
Daher kann man es sich mit Wrappern einfacher machen, wie das gezeigte
PolymorphicContainer.
Die gezeigte staticIteration Funktion ermöglicht ein Iterieren über die
Elemente eines tuple, aber das ist keine echte Schleife, im erzeugten
Code wird das komplett ausgerollt.
Walter T. schrieb:> Irgendwie fürchte ich gerade, dass ich so oder so um einen Codegenerator> nicht herumkomme.
Doch. Wie gezeigt ist das Problem lösbar. Man darf aber nicht erwarten
dass das mit einfachsten Mitteln direkt geht. Code-Generatoren sind im
Endeffekt meistens mehr Arbeit als sie helfen.
Walter T. schrieb:> Sehr ich das richtig, dass ich über ein tuple nicht in einer> for-Schleife mit einer Auto-Variable drüberiterieren kann, und bei der> Initialisierung an zwei Stellen (in der Deklaration und in der> Initializer List) Buch führen muss, um welchen Datentyp es sich handelt?
In einem range-for geht das nicht nein, da die Typen unterschiedlich
sind und sich keinen Iterator teilen. In einem generischen Algorithmus
geht das schon.
Walter T. schrieb:> Das würde es für eine Liste mit > 100 Einträgen eigentlich schon direkt> disqualifizieren.>> Irgendwie fürchte ich gerade, dass ich so oder so um einen Codegenerator> nicht herumkomme.
Nachdem du nachwievor kein Wort darüber verlierst was du vor hast wird
dir niemand weiterhelfen können. Fakt ist, dass C++ aktuell über keine
Reflection verfügt. Die Möglichkeiten der Metaprogrammierung werden zwar
ständig ausgebaut, sind aber dadurch trotzdem noch begrenzt.
Vincent H. schrieb:> Nachdem du nachwievor kein Wort darüber verlierst was du vor hast
Ich habe es oben angedeutet:
Beitrag "Re: C++ : Mit for-Schleife über Objekte verschiedener Klassen iterieren"
Man stelle sich die Tabelle/Array/Sonstwas mit > 200 Einträgen vor.
Viele Variablen unterschiedlichens Typs, aber alle jeweils mit einer
Funktion gleichens Namens.
Vielleicht sind die "polymorphic container" genau die Lösung. Ich muss
sie mir mal in Ruhe angucken.
Walter T. schrieb:> Man stelle sich die Tabelle/Array/Sonstwas mit > 200 Einträgen vor.> Viele Variablen unterschiedlichens Typs, aber alle jeweils mit einer> Funktion gleichens Namens.
Der Übersichtlichkeit halber auf godbolt ->
https://godbolt.org/z/Yxn97e
und mit C++17 kompiliert. C++20 erfordert offensichtlich nicht mehr die
Vorab-Auflistung des Datentyps im Tupel.
Das ist ja regelrecht brauchbar. Ich bin entzückt.
Jetzt gönne ich mir erst einmal im Laufe des Tages ein
Toolketten-Update.
Ist hier gerade ein Beitrag zuviel gelöscht worden? Ich erinnere mich an
o
Vincent H. schrieb:> Sollt mit C++17 eigentlich auch gehn.
Tut es auch. Ich habe es angepasst, bevor ich das Kompilieren probiert
habe, weil mein Buch "ab C++20" dazu schreibt.
Rolf M. schrieb:> Mark B. schrieb:>> Wieso denn Blödsinn? Selbstverständlich ist es möglich, es so zu machen>> wie von Gähn beschrieben.>> Nur arbeitet dein Code halt nicht so wie beschrieben. Er speichert keine> Fahrzeuge im vector, sondern Zeiger.
Es war doch zu Beginn von einem Array die Rede:
Walter T. schrieb:> diese in eine Art array zu packen und mit einer for-Schleife> darüberzuiterieren?
Wenn es ein Array sein soll, geht es nur so. Wenn es auch eine andere
Datenstruktur sein kann, geht es auch anders. Ich denke der
Themenersteller ist noch nicht so weit um genau entscheiden zu können,
was denn für seinen Anwendungsfall besser geeignet wäre. ;-)
Ich habe "eine Art Array" für unspezifisch genug gehalten. In Matlab
heißen die "Cell Array", in Python "list". Was in C++ der passende
Datentyp ist, war ja gerade die Frage. Eine geordnete Menge
unterschiedlicher Datentypen.
In Matlab sind die "Cell Arrays" von der Nutzung wie structs mit Index
anstelle Schlüsselwort. Also das absolute Gegenteil von exotisch. (Aber
Matlab ist ohnehin etwas außergewöhnlich. Dort kann man auch sehr bequem
über die Felder von structs iterieren.) In Python haben "lists" auch
keinen Seltenheitswert. In C++ scheint das Anliegen so exotisch zu sein,
dass es schwierig ist, die Frage danach zu formulieren.
Walter T. schrieb:> In C++ scheint das Anliegen so exotisch zu sein,> dass es schwierig ist, die Frage danach zu formulieren.
Die Frage ist nur deshalb schwierig zu formulieren, weil du anscheinend
nicht weißt, was du eigentlich fragen willst.
Eine Antwort auf deine nicht gestellte Frage ist: C++ ist wie C eine
streng typisierte Sprache, Matlab und Python sind das nicht.
Oliver
Oliver S. schrieb:> Die Frage ist nur deshalb schwierig zu formulieren, weil du anscheinend> nicht weißt, was du eigentlich fragen willst.
Wenn man einen Ausdruck so präzise formulieren kann, dass ihn ein
Compiler versteht, benötigt man kein Forum.
Walter T. schrieb:> Irgendwie fürchte ich gerade, dass ich so oder so um einen Codegenerator> nicht herumkomme.
WEnn es um hunderte von konstanten Objekten geht, ist das sowieso das
Mittel der Wahl.
Nur ein Hinweis am Rande:
Die statischen, zur Compilezeit ausgewerteten Datentypen wie tuple
brauchen genau das, nämlich Compiletime. Die aktuellen Compiler sind
inzwischen zwar dafür gerüstet, aber ein tuple mit ein paar hundert
Elementen könnte da doch zu unliebsamen Überraschungen führen.
Ein gcc 4.1 (oder so) crasht schon bei mehr als einer handvoll
Elementen...
Oliver
Walter T. schrieb:> Ich habe "eine Art Array" für unspezifisch genug gehalten. In Matlab> heißen die "Cell Array", in Python "list". Was in C++ der passende> Datentyp ist, war ja gerade die Frage. Eine geordnete Menge> unterschiedlicher Datentypen.>> In Matlab sind die "Cell Arrays" von der Nutzung wie structs mit Index> anstelle Schlüsselwort. Also das absolute Gegenteil von exotisch. (Aber> Matlab ist ohnehin etwas außergewöhnlich. Dort kann man auch sehr bequem> über die Felder von structs iterieren.) In Python haben "lists" auch> keinen Seltenheitswert. In C++ scheint das Anliegen so exotisch zu sein,> dass es schwierig ist, die Frage danach zu formulieren.
Normalerweise würde ich dafür eine
std::list verwenden und Zeiger auf
die Basisklasse darin speichern. Je
nachdem, welche Anforderungen du noch
an den Container hast (Zugriff per Key?,
Sortierung?, etc.), kämen noch andere
in Betrachtung: std::map, std::set,
std::vector.
merciless
Die Frage ist halt, was willst du denn im List Body dann mit den
Objekten machen? Das Äquivalent zur Python list wäre vmtl sowas wie
std::vector<std::any>. Da passen die Objekte leicht rein, und man kann
auch leicht darüber iterieren, nur danach irgendwas damit zu tun wird
schwer.
Etwas sinnvoller wäre ein std::vector<std::variant<...>>. Mit std::visit
kann man dann relativ lesbaren Code schreiben, der die einzelnen Typen
z.B. per function template specialization behandelt.
Oder eben die bereits vorgeschlagene Vererbungshierarchie. Für dein
Beispiel mit den Geometrieelementen scheint mir das die geeignetste
Lösung. Sind dir die vtables zu groß, kannst du sie dir selber
schreiben, z.B. per templates.
Dirk K. schrieb:> std::list
Wie selbst der C++-Standard selber schreibt, ist std::vector die beste
Wahl für die allermeisten Anwendungen. So wohl auch hier.
Alles in allem klingt die Anwendung von Walter aber sehr danach, daß er
ein „Array“ von zur Compilezeit bekannten konstanten Elemente sucht.
Da ist std::tuple schon nicht verkehrt, dann gibt es gar keinen run time
overhead.
Oliver
Ich finde, ziemlich viele Anwendungen von std::array lassen sich durch
eine initializer list ersetzen, z.B. der oben genannte.
auto const items = {1, 2, 3, 4};
for (auto item: items) { ... }
Oliver S. schrieb:> Dirk K. schrieb:>> std::list>> Wie selbst der C++-Standard selber schreibt, ist std::vector die beste> Wahl für die allermeisten Anwendungen. So wohl auch hier.
Jein, wenn z.B. viele Inserts() gemacht werden,
ist std::vector ungeeignet, weil sonst zu oft
umkopiert werden muss (std::vector garantiert,
dass die Einträge im Speicher hintereinander
liegen. Ist der anfänglich reservierte Speicher
voll, wird neu allokiert und der ganze Inhalt
umkopiert.). Noch schlimmer wird es beim
Löschen von Einträgen. std::list wäre in dem
Fall performanter.
merciless
Dirk K. schrieb:> Jein, wenn z.B. viele Inserts() gemacht werden,> ist std::vector ungeeignet,
Deshalb gibt es std::list, und für andere Anwendungsfälle auch noch die
andere Container, was ja völlig ok ist.
In einer älteren Version des Standards oder in seinem Umfeld stand m.E
sinngemäß mal drin:
Nimm immer std::vector. Wenn nicht, musst du es ausführlich begründen.
Die Anwendung des TO sieht jetzt nicht danach aus, daß er was anderes
braucht.
Oliver
Oliver S. schrieb:> Nimm immer std::vector. Wenn nicht, musst du es ausführlich begründen.
Wenn die Menge an Objekten sowieso fest ist und sich zur Laufzeit nicht
ändert, wozu dann ein Vector? Dann tut es doch auch ein schnödes Array?