Dynamisches Array
-
vivess schrieb:
Echt?
Echt.
Das ist auch ein Grund, warum rohe C Zeiger nicht in C++ Programmiererhände gehören.
Du musst dich dabei nämlich um alles selbst kümmern.
Und das ist nichts für Anfänger.
Und außerdem hast du mit mdata gar kein Array. Du hast einen Zeiger auf Lied. Und ein Zeiger ist kein Array und auch nicht umgekehrt.
Du musst dir den Beginn sowieso merken, z.B. für deinen Destruktor. Wie soll delete[] denn funktionieren wenn es den Wert bei new nicht übergeben bekommt sondern irgendwas anderes?
Rohe C Zeiger gehören nicht in C++ Programmiererhände, dafür gibts Referenzen, Smartpointer und für dein Problem Container"klassen".
Und deswegen ist deine "Aufgaben"stellung sinnfrei und dein Lehrer der Inkompetenz überführt.
-
Wutz schrieb:
vivess schrieb:
Echt?
Echt.
Das ist auch ein Grund, warum rohe C Zeiger nicht in C++ Programmiererhände gehören.Ach? Spannend, dass du C++-Entwicklern absprichst, mit Zeigern zu hantieren. Bleib lieber im C-Forum.
Du musst dich dabei nämlich um alles selbst kümmern.
Stimmt.
Und das ist nichts für Anfänger.
Wir waren alle Anfänger und mussten das lernen. Daher ist das zum Lernen genau passend!
Und außerdem hast du mit mdata gar kein Array. Du hast einen Zeiger auf Lied. Und ein Zeiger ist kein Array und auch nicht umgekehrt.
Und jetzt muss man nur noch wissen, dass man mit x[N] auf das N-te Array-Element von x zugreift, egal ob x ein Array oder ein Zeiger auf das erste Array-Element ist. Und schon ist die Verbindung hergestellt.
Rohe C Zeiger gehören nicht in C++ Programmiererhände, dafür gibts Referenzen, Smartpointer und für dein Problem Container"klassen".
Die sind aber nicht immer geeignet. Es ist - auch in C++ - nichts an rohen Pointern verkehrt! Was oft verkehrt ist, sind nicht-smarte besitzende Pointer. Man kann aber auch erst einmal new+delete lernen, um danach zu erfahren, wie es oftmals besser ist. Man muss sich auch als C++-Entwickler mit Pointern auskennen.
Und deswegen ist deine "Aufgaben"stellung sinnfrei und dein Lehrer der Inkompetenz überführt.
Ich finde es nicht abwegig, zu Lernzwecken etwas vector-ähnliches selbst zu implementieren.
-
Wutz schrieb:
Rohe C Zeiger gehören nicht in C++ Programmiererhände, dafür gibts Referenzen, Smartpointer und für dein Problem Container"klassen".
Immer wieder dieselbe Soße, es hört einfach nicht auf.
C-Zeiger sind ein fundamentaler Bestandteil von C++. Ohne C-Zeiger zu verstehen, kann man auch nur oberflächliches Verständnis für Smart Pointers erlangen. Inkompetent sind eher diejenigen, die dies nicht wissen (wollen).
Da draußen sind Tausende von C++-Programmieren, die - aus welchen Gründen auch immer (Legacy Code, Code Policies, Low-Level- und Library-Programmierung ...) - C-Zeiger benutzen, und diese alle als inkompetent hinzustellen ist ein Frechheit
-
Wir haben die gleiche aufgabe schon mit vektoren gelöst.
Ich hätte da aber nun noch ein problem und zwar habe ich ja zwei klassen, einmal für meine musikdatenbank deren variablen und funktionen:
enum genre {Pop,Rock,Klassik,HardRock}; class Lied { public: std::string titel; std::string interpret; int erscheinungsjahr; double laenge; genre genre1; .. void neuer_eintrag(Lied& liedobjekt); .. };
und die funktionen/kontruktoren etc. von meinem DynArray:
class DynArray { public: DynArray(int newCapacity); DestrukDynArray(); Lied& at(int index); .. void push_back(Lied elem); .. Lied* m_data; int m_size; .. };
Und dann hab ich zwei .cpp wo ich dann jeweils die funktionen für die zwei klassen programmiere. Nun hab ich aber das problem, das ich da wo ich die funktionen für die Klasse "Lied" programmieren will, irgendwie nicht so recht auf die funktionen und variablen von der Klasse DynArray zugreifen kann. Wenn ich z.b. ein Liedobjekt mit titel, interpret etc. anlege und etwas hineinschreibe, und dann das liedobjekt in die DynArray funktion push_back reinstecken will
DynArray.push_back(lied1);
bekomm ich die Fehlermeldung:
error: expected unqualified-id before '.' token
Wenn ich auf z.b. DynArray.m_size zugreifen will
DynArray.m_size
bekomm ich
error: expected primary-expression before '.' token
Weiß wer was ich da falsch mach? Ich hab in beiden .cpp dateien #include "dynarray.h" stehen (in dynarray.h hab ich beide klassen-definitionen stehen).
-
Klassen sind keine Objekte, Objekte sind keine Klassen.
Wenn du schreibst DynArray.push_back(foo), dann ist das ungefähr so, als würdest du versuchen
int = 5;
Da würdest du auch nicht erwarten, dass das klappt.
Achte bei dem Design deiner Klassen auf strikte Trennung von Zuständigkeiten:
+ Ein Lied ist nur das, ein Lied. Es weiß nichts von Dynarrays oder Liedersammlungen.
+ Ein DynArray ist nur das, ein dynamisches Array. Es weiß nichts von Liedern oder Liedersammlungen.
+ Eine Liedersammlung ist nur das: Eine Liedersammlung. Sie besteht wahrscheinlich aus einem DynArray von Liedern und weiß was DynArrays und Lieder sind; aber sie macht nichts von dem, was Aufgabe eines Liedes oder eines DynArrays ist.Der zweite Punkt ist vielleicht etwas schwierig, wenn du noch keine Templates kennst. In dem Fall solltest du ein DynLiedArray machen, welches ein dynamisches Array von Liedern ist, aber nicht die Aufgaben einer Liedersammlung hat.
-
SeppJ schrieb:
Klassen sind keine Objekte, Objekte sind keine Klassen.
Diese Eingrenzung gilt für C++. Vernünftige OO-Sprachen haben diese Einschränkung nicht, da sind auch alle Klassen Objekte und auch so zu gebrauchen.
-
Wutz schrieb:
Vernünftige OO-Sprachen haben diese Einschränkung nicht
Aber natürlich sind das keine vernünftigen Sprachen, weil sie OOP haben!
Die einzig wahre Sprache ist C. Alles andere ist für nubs.
-
SeppJ schrieb:
Klassen sind keine Objekte, Objekte sind keine Klassen.
Wenn du schreibst DynArray.push_back(foo), dann ist das ungefähr so, als würdest du versuchen
int = 5;
Da würdest du auch nicht erwarten, dass das klappt.
Achte bei dem Design deiner Klassen auf strikte Trennung von Zuständigkeiten:
+ Ein Lied ist nur das, ein Lied. Es weiß nichts von Dynarrays oder Liedersammlungen.
+ Ein DynArray ist nur das, ein dynamisches Array. Es weiß nichts von Liedern oder Liedersammlungen.
+ Eine Liedersammlung ist nur das: Eine Liedersammlung. Sie besteht wahrscheinlich aus einem DynArray von Liedern und weiß was DynArrays und Lieder sind; aber sie macht nichts von dem, was Aufgabe eines Liedes oder eines DynArrays ist.Der zweite Punkt ist vielleicht etwas schwierig, wenn du noch keine Templates kennst. In dem Fall solltest du ein DynLiedArray machen, welches ein dynamisches Array von Liedern ist, aber nicht die Aufgaben einer Liedersammlung hat.
Hm ok, ich versteh jetzt nicht so ganz.
Punkt 1 wäre dann ja im grunde einfach ein struct Lied, wo ich den Typ Lied definier.
Punkt 2 wäre die Klasse DynArray mit deren kontruktoren/funktionen/variablen, und die Klasse ist vorgegeben von der aufgabenstellung. Gehe nicht davon aus das wir die verändern dürfen.
Punkt 3 wäre dann eine Klasse liedersammlung mit deren funktionen. Aber wie schreib ich denn die klasse Liedersammlung, das ich dort funktionen von der klasse DynArray verwenden darf(bzw. aufrufen darf)? In der klasse liedersammlung hab ich ja z.b. die funktion "neuer eintrag hinzufügen" wo der benutzer dann halt titel, interpret, etc. eingibt, diese Eingaben werden in ein Objekt Lied gespeichert, und dieses Objekt will ich dann der funktion DynArray.push_back() zuschicken damit die das in das dynarray verwurstelt.
-
Du scheinst immer noch nicht den Unterschied zwischen Klassen und Objekten derselben verstanden zu haben.
Eine Klasse ist wie eine Lexikonbeschreibung eines Wortes. Im Lexikon wird beispielsweise erklärt, was ein 'Hund' ist, wie er aussieht, wie er sich verhält.
Ein Objekt einer Klasse ist eine konkrete Realisierung einer solchen Beschreibung. Also ein richtiger, echter Hund.
Du kannst die Beschreibung im Lexikonartikel nicht streicheln und sie wird nie bellen. Das kann nur ein echter Hund. Genausowenig kann du der Beschreibung eines DynArrays ein Lied hinzu fügen. Du brauchst eine konkrete Objektinstanz dafür. Deine Liedersammlung sollte eine Instanz von DynArray enthalten.
-
SeppJ schrieb:
Deine Liedersammlung sollte eine Instanz von DynArray enthalten.
Und wie mach ich das?
DynArray.push_back() scheint also nur auf die Deklaration "zuzugreifen", aber nicht auf die definition?
(nur um Missverständnisse zu vermeiden, push_back und die ganzen anderen Funktionen hab ich natürlich auch programmiert in einer eigenen .cpp
void DynArray::push_back(Lied elem) { .. .. }
)
-
Oder praktisch erklärt:
class Foo { }; Foo bar; // Foo ist die Klasse, bar ein Objekt vom Typ Klasse
Das Wort "Klasse" hast du doch auch im echten Leben.
Es gibt die Klasse der Säugetiere, du bist als Mensch ein Objekt der Klasse der Säugetiere.
Oder die Klasse der geraden Zahlen, bei der 2,4,6,... Objekte wären.
-
Gehe nicht davon aus das wir die verändern dürfen.
<anekdote>
lustigerweise hängt genau das aber sehr stark von deinem lehrer ab. an meiner uni (damals) bei einer der typischen algorithmen-und-datenstrukturen-veranstaltungen haben teams von leuten verschiedene such-algorithmen zu implementieren gehabt (semesterprojekt), die dann gegeneinander angetreten sind (vereinfacht gesagt: gewonnen hat, wer am schnellsten ist). eine gruppe hatte allerdings die glorreiche idee, dass sie nur dann gewinnen kann, wenn sie einen anderen algorithmus als den in der aufgabenstellung vorgegebenen verwenden würde. war natürlich kein problem.
das zeigt nämlich, dass sich diese gruppe bewusst war, was vor- und nachteile bestimmter algorithmen sind.</anekdote>
was SeppJ wohl meinte (mit trennung von zuständigkeiten):
class Lied { //... void neuer_eintrag (Lied& lied); };
einem lied willst du ein neues lied hinzufügen? das macht schon auf deutsch keinen sinn, geschweige denn auf C++. genau genommen ergibt das in keiner einzigen programmiersprache sinn. es ist zwar zumindest grammatikalisch (syntaktisch) korrekt, aber un-sinnig.
Aber wie schreib ich denn die klasse Liedersammlung, das ich dort funktionen von der klasse DynArray verwenden darf
SeppJ hat dir die abstrakte erklärung geliefert; jetzt eine konkrete noch dazu:
funktionen, die du als teil einer klasse definierst, haben einen versteckten parameter: denthis
-zeiger, der ihnen übergeben wird. dieser zeiger zeigt auf die aktuelle instanz der klasse. wenn du also eine funktion aus der klasse DynArray verwenden willst, musst du ihr einenthis
-zeiger mitübergeben. in einer solchen funktion (üblicherweise nennt man das in C++ elementfunktion) kannst du dann auf andere elemente der jeweiligen instanz zugreifen.class Lied { string name; void print_name(); }; //... void Lied::print_name() { cout << name << endl; //ist äquivalent zu cout << this->name << endl; //bloß - woher kommt "this" und worauf zeigt es? //antwort: auf eine konkrete instanz! } //... die konkrete instanz muss erst irgendwo geschaffen werden! Lied einLied; //so z.B. einLied.print_name(); //this zeigt jetzt auf "einLied" Lied* zweitesLied = new Lied; //oder so zweitesLied->print_name(); //this ist jezt zweitesLied einLied.print_name(); //hier ist this ein zeiger auf einLied //das ganze wird - vom compiler - so implementiert: //"behind the scenes" struct Lied { string name; }; void print_name (Lied* this_) { cout << this_->name << endl; } //... Lied einLied; print_name(&einLied); Lied* zweitesLied = new Lied; print_name(zweitesLied); print_name(&einLied);
wie ich schon ganz am anfang gesagt hab: stell dir einfach vor, du hast zwei DynArrays. wie würdest du dann die aufgabe lösen? stell dir deine klasse liedsammlung vor, die *zwei* DynArrays verwalten muss: eines namens
guteLieder
und eines namensschlechteLieder
.class LiedSammlung { //... void neuer_eintrag (const Lied& lied); }; //... void LiedSammlung::neuer_eintrag (const Lied& lied) { //if lied.popularitaet() < 50 //zu den guten liedern hinzufügen //else //zu den schlechten liedern hinzufügen }
PS. es wirkt, als würdest du dich wirklich und selbständig mit dem problem auseinandersetzen. solchen fragestellern wie dir hilft man hier gerne!
-
Ich geh an die Decke..
Das mit dem this werd ich heut nicht mehr verstehen
Was SeppJ und Ethon wohl gemeint haben war hoffe ich irgendwie sowas in der art:
class liedersammlung { public: void neuer_eintrag(); int alle_eintraege_anzeigen(); size_t details_von_eintrag_anzeigen(); int eintrag_bearbeiten(); int eintrag_loeschen(); int menu(); DynArray a; };
Also das ich dann in den funktionen von liedersammlung DynArray-Funktionen mit z.b. a.push_back() aufrufen kann. Das funktioniert auch soweit, nur wie krieg ich dann ein DynArray gescheit angelegt. Irgendwie muss ich ja in dem einstiegspunkt in main schon ein DynArray anlegen. Das lustige ist ja das diese Kontruktoren was ganz eigenartiges zu sein scheinen. Ich kann einfach in der main Funktion
DynArray(5);
schreiben und der macht das einfach ohne vorher sowas schreiben zu müssen
DynArray a; a.DynArray(5);
Das ist ja ganz lustig, aber wenn ich dann in der Klasse liedersammlung meine Funktion neuer_eintrag() habe
void liedersammlung::neuer_eintrag() { Lied lied1; cout<<"Gebe Titel, Interpret, Erscheinungsjahr, Laenge des Liedes und Genre an!\nTitel: "; cin>>lied1.titel; cout<<"Interpret: "; cin>>lied1.interpret; cout<<"Erscheinungsjahr: "; cin>>lied1.erscheinungsjahr; cout<<"Laenge des Liedes in der Form Minute.Sekunde: "; cin>>lied1.laenge; a.push_back(lied1); }
Hat der ja nichts gescheites zum push-backen weil ich ja vorher kein Array angelegt habe und deswegen ja m_data und alles mumpitz sind. Die aufgabe treibt mich echt in den Wahnsinn. Weiß wer wie man hinbekommt? Ich hab aber irgendwie so das Gefühl so wie ich mir das jetzt zurecht denk ist es auch wieder alles falsch
:p
-
class liedersammlung { public: void neuer_eintrag(); int alle_eintraege_anzeigen(); size_t details_von_eintrag_anzeigen(); int eintrag_bearbeiten(); int eintrag_loeschen(); int menu(); // Daten sollten private sein!!! private: DynArray a; };
Es ist üblich den Zugriff auf die Daten einer Klasse zu kapseln und nur über die Methoden der Klasse zu ermöglichen. Da du keinen Konstruktor deklariert hast, wird der Compiler einen Standardkonstruktor anlegen. Sobald du eine Instanz deiner Klasse erzeugst, wird damit auch ein DynArray a automatisch angelegt (innerhalb der Instanz).
void liedersammlung::neuer_eintrag() { Lied lied1; cout<<"Gebe Titel, Interpret, Erscheinungsjahr, Laenge des Liedes und Genre an!\nTitel: "; cin>>lied1.titel; cout<<"Interpret: "; cin>>lied1.interpret; cout<<"Erscheinungsjahr: "; cin>>lied1.erscheinungsjahr; cout<<"Laenge des Liedes in der Form Minute.Sekunde: "; cin>>lied1.laenge; a.push_back(lied1); // a wurde vom Konstruktor erzeugt }
void main() { liedersammlung lieder; // Aufruf des Standardkonstruktors von liedersammlung lieder.neuer_eintrag(); // Lied hinzufügen }
Edit: Ich hatte was überlesen
-
Hmm ok aber das bringt mir jetzt auch nicht so wirklich weiter glaub ich.
Mein problem ist ja mittlerweile das wenn ich z.b. den Kontruktor
DynArray::DynArray(int newCapacity) { m_data = new Lied[newCapacity]; m_data_anfang = m_data; m_capacity = newCapacity; m_size=0; }
in main mit
DynArray a(5);
aufrufe und dann ein Objekt Lied erstelle und irgendwas reinschreibe
Lied lied1; lied1.titel="test"; lied1.interpret="interpret"; lied1.erscheinungsjahr=3849; lied1.laenge=5.3;
Und dann steck ich das lied1 in meine push_back funktion rein
void DynArray::push_back(Lied elem) { m_size+=1; if(m_size == m_capacity) { resize(2*capacity()); *m_data=elem; } else *m_data=elem; m_data+=1; // m_data auf den nächsten index zeigen lassen }
Und dann schreib ich in main
cout<<a.m_data->titel;
Was natürlich nichts ausgibt, weil ich in der push_back-Funktion nicht das m_data der Instanz 'a' verändert habe. Es würde funktionieren wenn ich von der Instanz a in der main das
a.m_data
als Zeiger dem push_back übergebe und der hantiert dann mit dem a.m_data herum. Aber das ist denke ich nicht Sinn der sache.
Ich hab mal etwas gesucht und es gibt vllt irgendwie die Möglichkeit alle Dyn-Array variablen als static zu machen, was die wohl dann irgendwie global machen, aber das ist denke auch nicht gut.
mein kernproblem ist nun einfach das ich es nicht hinkrieg das meine DynArray-funktionen wie z.b. das push_back oder auch der konstruktor mit den Variablen aus z.b. einer Instanz die ich in main aufrufe hantieren zu lassen.
-
Du brauchst kein DynArray in main.
-
Na, aber irgendwo muss ich ja ein dynarray anlegen.
aber ich gebs jetzt auch auf. Geht vllt. einfach nicht mit den Sachen die ich bis jetzt kann. drecks aufgabe, schmorr in der hölle.
-
vivess schrieb:
Na, aber irgendwo muss ich ja ein dynarray anlegen.
Ja, in Liedersammlung
aber ich gebs jetzt auch auf. Geht vllt. einfach nicht mit den Sachen die ich bis jetzt kann. drecks aufgabe, schmorr in der hölle.
Du hast etwas grundlegendes nicht verstanden. Das hat nichts mit dieser Aufgabe zu tun. Solange du das nicht verstehst wirst du ziemlich Probleme mit deinen weiteren Aufgaben haben.
-
aber in den folien steht auch ein feuchter dreck dazu. kann ja nicht sein das ich mir da alles selber ausm Hintern ziehen muss.
-
Was unterscheidet Dynarray von std::string?
Was unterscheidet "Titel" von "Array von Liedern"?Wenn du Titel nicht in main erzeugen musst, warum dann das Array?