Mehrere Objekte erstellen in einem Array
-
Ich möchte einfach nur mehrere Objekte von einer Klasse erstellen und in einem Array speichern. Bei einzelnen Objekten klappt das auch super, nur mit mehreren per Schleife komm ich da bisher nicht weiter.
Habe schon einiges durch getestet sowohl mit den Std::Array als auch mit den Array<> und vector<> Containern ab c++11 geklappt hat es aber nie.#include <iostream> #include <string> #include <vector> using namespace std; class test{ int ID; string Name; public: test(int id, string na) : ID(id), Name(na) {} int getID(){ return ID; } string getName(){ return Name; } }; struct liste{ string names[5] = { "Mike", "Ann", "Han", "Susan", "Knut-Hansen", }; }; int main(){ liste liste; vector<test> objTest(5); int i=0; for(string cname : liste.names){ objTest[i] = {test(i, cname)}; i++; } for(int i=0; i<5; i++){ cout << objTest[i].getName(); } };
G++ meldet dort:
39:1: error: expected unqualified-id before numeric constant
35:22: error: 'class std::vector<test>' has no member named 'getName'Ich bin mir sicher das es eine ganz einfache Lösung geben muss, ich finde sie nur leider nicht
-
Ahh, klar. Der Fehler in Zeile 39 deines 37-Zeilen-Programms. Vielleicht brauchst du Hilfe?
Das Programm, das du hier zeigst, hat einen komplett anderen Fehler, in Zeile 28, der nicht zu deiner Fehlermeldung passt. Dort erstellst du einen Vector mit 5 Objekten der Klasse
test
. Deine Klassetest
kann man aber nicht ohne Argumente erzeugen (sie benötigtid
undna
), daher kracht es dort. Die Idee, erst "leere" Platzhalterobjekte zu erzeugen und dann zu überschreiben (was du wohl in Zeile 31 vor hast) ist sehr unüblich, da unnötig umständlich. Das besondere am Vector ist ja gerade das Mitwachsen, also nutze es auch: Erstell einen leeren Vector, dann nutzepush_back
oderemplace_back
um deine 5 Elemente anzuhängen.
-
Danke erstmal für deine Hilfe, leider kommt der Fehler wirklich auf einer Position nach dem Ende des Codes. Ich hab eine Leerzeile zur besseren übersicht beim Übertragen entfernt, bei Ausführung waren es also 38 Zeilen.
Eigentlich würde ich auch eher ein normales Array für den Zweck bevorzugen statt dem vector, da ich die objects eh nur einmalig initialisieren und danach nicht mehr ändern muss.
-
@loolery sagte in Mehrere Objekte erstellen in einem Array:
da ich die objects eh nur einmalig initialisieren und danach nicht mehr ändern muss.
struct foo_t { char const * const foo; unsigned id; }; // ... foo_t foo[] = { { "Mike", 0 }, { "Ann", 1 }, { "Han", 2 }, { "Susan", 3 }, { "Knut-Hansen", 4 } };
fertig, aber eigentlich:
char const * const foo[] = { "Mike", "Ann", "Han", "Susan", "Knut-Hansen" };
-
@loolery sagte in Mehrere Objekte erstellen in einem Array:
Danke erstmal für deine Hilfe, leider kommt der Fehler wirklich auf einer Position nach dem Ende des Codes.
Das kommt dir nicht irgendwie komisch vor? Offensichtlich übersetzt du einen ganz anderen Code als du denkst.
-
@Swordfish sagte in Mehrere Objekte erstellen in einem Array:
@loolery sagte in Mehrere Objekte erstellen in einem Array:
da ich die objects eh nur einmalig initialisieren und danach nicht mehr ändern muss.
struct foo_t { char const * const foo; unsigned id; }; // ... foo_t foo[] = { { "Mike", 0 }, { "Ann", 1 }, { "Han", 2 }, { "Susan", 3 }, { "Knut-Hansen", 4 } };
fertig, aber eigentlich:
char const * const foo[] = { "Mike", "Ann", "Han", "Susan", "Knut-Hansen" };
Danke für deine Mühe, aber das hilft mir leider beim eigentlichen Problem nicht weiter. Mir geht's allein um das Speichern mehrerer Objekte per Schleife in ein Array, die Liste und alles andere drum herum diente nur dem besseren Verständnis hier.
Ich verstehe bisher leider nicht warum es in C++ so simple ist ein Array einzeln mit Objekten aus einer Klasse zu füttern, aber sobald man das mit einer Schleife tun möchte nicht mehr auf dem selben Weg möglich ist.
-
Hast du meine Antwort gelesen? Es ist super-simpel, einfacher noch als dein jetziger Code. Du kommst bloß mit deiner Entwicklungsumgebung nicht zurecht und übersetzt wer weiß was, was nicht dein Code ist.
vector<test> objTest; ... objTest.push_back(test(i, cname));
-
@SeppJ sry, ja hat ich gelesen und funktioniert auch, danke.
Ich versteh halt trotzdem nicht wieso es mit dem stdArray ohne weitere includes nicht geht und ich auf Vector ausweichen muss um diese simple Sache in einer Schleife zu bewerkstelligen.
-
Weil ein statisches Array nie "leer" sein kann, es hat ja schließlich genau seine Größe. Ein Array mit 5 Elementen hat immer 5 Elemente. Vom Anfang seiner Lebensdauer bis zum Ende. Und irgendwo müssen die Elemente, die da ganz am Anfang beim Erstellen drin sind, ja herkommen. Nun kann man deine Klasse
test
aber nicht einfach so aus dem Nichts erzeugen (siehe meine erste Antwort, die alles komplett erklärt hatte…), denn sie hat schließlich zwei Argumente. Also musst du beim Erstellen eines Arrays der Klassetest
mit 5 Elementen auch diese 5 Elemente (oder die Argumente dafür) angeben. Das geht dann auch problemlos, wenn du das so machst! Aber irgendwie später Sachen in das Array einfügen geht halt nicht, denn das ist ja gerade der Unterschied zwischen Vector und Array, dass das bei dem einen geht und bei dem anderen nicht.Oder anders gesagt: Wenn das so gehen würde, wie du es vor hast, man also einfach so
test foo[5]; # oder besser: std::array<test, 5> foo;
schreiben könnte, ohne die 5
test
-Elemente anzugeben: Was für Werte vonID
undName
hätte dann deiner Meinung nach das Elementfoo[2]
?
-
@SeppJ Andere Sprachen bekommen das ja sonst hin den Speicher beim laden der Array direkt zu reservieren für die spätere Belegung, davon bin ich bisher wohl einfach zu verwöhnt gewesen. Aber danke für deine doppelte und ausführliche Erklärung.
-
@loolery sagte in Mehrere Objekte erstellen in einem Array:
@SeppJ Andere Sprachen bekommen das ja sonst hin den Speicher beim laden der Array direkt zu reservieren für die spätere Belegung, davon bin ich bisher wohl einfach zu verwöhnt gewesen. Aber danke für deine doppelte und ausführliche Erklärung.
Welche denn? Es geht hier ja nicht um Reservierung von Speicher, sondern um das Erzeugen von Objekten. Ein
test foo[5]
erzeugt 5 Test-Objekte, nicht 5 (möglicherweise auf nullptr gesetzte) Pointer auf Objekte. C++ arbeitet direkt mit Objekten, nicht implizit mit Pointern/Referenzen, außer du nutzt diese explizit.Wenn du nur Speicher reservieren willst:
vector.reserve()
-
@loolery sagte in Mehrere Objekte erstellen in einem Array:
@SeppJ Andere Sprachen bekommen das ja sonst hin den Speicher beim laden der Array direkt zu reservieren für die spätere Belegung, davon bin ich bisher wohl einfach zu verwöhnt gewesen. Aber danke für deine doppelte und ausführliche Erklärung.
Nein, solche Sprachen gibt es nicht. Du verstehst das Problem nicht, wenn du denkst, solche Sprachen könnte es geben. Es ist ein Logikfehler in deinem Programm (oder in deinem Verständnis). Das hat mit egal welcher Sprache nichts zu tun, denn Logik ist in jeder Sprache gleich, und somit auch Fehler in der Logik.
Du kannst nicht Wahrhaft behaupten "Ich habe einen Korb mit 5 Äpfeln" ohne dass du 5 Äpfel in dem Korb hast. Egal ob auf Deutsch, C++, oder jeder anderen Sprache. "Ich habe einen Korb mit 5 Äpfeln" ist nicht das gleiche wie "Ich habe einen Korb mit Platz für 5 Äpfel". Letzteres kann auch wahr sein, ohne dass 5 Äpfel im Korb sind. Sowohl auf Deutsch, C++, oder jeder anderen Sprache. Ein statisches
array<Apfel, 5>
ist aber ein Korb in dem 5 Äpfel drin sind, nicht bloß ein Korb in dem Platz für 5 Äpfel ist. Wenn du so einen Korb mit 5 Äpfeln drin erstellst, dann müssen die 5 Äpfel irgendwo herkommen, ansonsten ist es kein Korb mit 5 Äpfeln drin.
-
Doch, Sprachen wie Java oder C#. Dort wird dann ein Array bei Referenztypen mit
null
bzw. in C# bei Wertetypen mit0
Byte Werten belegt. Und dann kann man nachträglich den einzelnen Array-Werten mittelsnew(...)
neue Werte zuordnen.
In C++ muß man aber dafür dann explizit Zeiger (bzw. Shared-Pointer) verwenden.
-
Wertetypen und Zeiger werden in C++ auch automatisch nullinitialisiert, wenn man nix sagt (was nicht einmal unbedingt
null
/0
heißt). Aber dastest
ist halt kein solcher Typ. Da ist in Java dasArray[test]
eben nur ein verkapptesArray[*test]
. Auch Java könnte nicht zaubern, und würde genauso meckern, wenn man einnew(test)
ohne Argumente macht.
-
@Th69 sagte in Mehrere Objekte erstellen in einem Array:
Doch, Sprachen wie Java oder C#. Dort wird dann ein Array bei Referenztypen ...
Ich habe das wichtige Wort mal markiert. Das ist aber doch hier genau der Unterschied! Es sind hier eben keine
test *foo[5]
oderstd::unique_ptr<test> foo[5]
deklariert (5 mögliche foos), sonderntest foo[5]
. Das sind 5 explizit verlangte foos. In C++ sind Klassen nicht automatisch Referenztypen. Wenn man dann sagt "aber mit Referenztypen geht das in Sprache XY", dann ist das eben nicht das gleiche.
-
Mal ganz einfaches Beispiel in vbsript, wie andere Sprachen das lösen, in C#, Java oder Basic überall so ähnlich auch möglich:
Class testklasse private myid Public Default Function Init(i) myid = i Set Init = Me End Function Public Property Let ID(byVal value) myid = value End Property Public Property Get ID ID = myid End Property End Class Dim objTest(4), ausgabe For i=0 To 4 'ReDim Preserve objTest(i) <- optional in der schleife auch erst reservierbar Set objTest(i) = (New testklasse)(i) Next For r=0 To UBound(objTest) ausgabe = ausgabe & " - " & r Next MsgBox(ausgabe)
Für mich als nicht Kernel-Treiber Hardcore coder ist es so zumindest deutlich angenehmer zu schreiben.
-
Das ist aber was anderes, als du in C++ programmiert hast. In deinem C++ Quelltext hast du explizit gesagt, dass du deine Objekte ausschließlich über einen Konstruktor mit 2 Parametern erzeugen möchtest. Dann darfst du dich also auch nicht beschweren, dass die Konstruktion sperrig ist, das hast du selbst so vorgegeben.
Du kannst natürlich deine Objekte mit ungültigen Werten default-konstruieren:
#include <string> class Test { int ID_ = -1; // Annahme: -1 ist eine ungültige ID std::string Name_; public: Test() = default; // Default Konstruktor erlauben Test( int id, std::string const& name ) : ID_( id ), Name_( name ) { } ... }
Damit kannst du auch "ungültige" Objekte erzeugen, aber dann stellt sich die Frage, warum du ungültige Objekte erzeugst und in einem Array/std::array ablegst, statt einen std::vector zu pflegen, der nur gültige Objekte enthält.
-
Das hat man doch schon versucht, Dir zu erklären ...
Das kannst Du in C++ ähnlich machen, allerdings hast Du dann eben kein Array von Objekten, sondern ein Array von Zeigern/Referenzen auf Objekte.
In Deinem Beispiel werden die Objekte erst in der Schleife erstellt (Zeile 19).Wenn Du in C++ ein Array mit:
Klasse array[5];
definierst, dann werden an der Stelle 5 Objekte vom Typ Klasse erstellt.
Dein Beispiel sähe in C++ etwa so aus:Klasse * array[5];
Dann hast Du ein Array, das nicht Objekte enthält, sondern Zeiger auf Objekte, und diese Zeiger kannst Du dann später auf Objekte zeigen lassen, die Du dann zB in einer Schleife erstellst ...
-
@DocShoe Das der Konstruktor nur 1 Parameter erfordert war gerade rein meiner Faulheit geschuldet, das gleiche mit 2 oder 20 Parametern zu machen ist kein großes Hexenwerk in vbs.
-
@loolery sagte in Mehrere Objekte erstellen in einem Array:
@DocShoe Das der Konstruktor nur 1 Parameter erfordert war gerade rein meiner Faulheit geschuldet, das gleiche mit 2 oder 20 Parametern zu machen ist kein großes Hexenwerk in vbs.
Das ist nicht das, was ich meinte. Du kannst in C++ steuern, wie Objekte erzeugt werden. Wenn du alle Konstruktoren bis auf einen deaktivierst, dann darfst du dich nicht beschweren, dass du Objekte nicht frei Schnauze konstruieren kannst, sondern auf diesen einen Konstruktor beschränkt bist.