Klasse und Frage zum Konstruktor
-
[quote="volkard"]
pumuckl schrieb:
Ist es nicht.
"Jetzt lerne ich C++" macht in Stunde 10vip@r scheint Folien zu "Jetzt lerne ich C++" zu benutzen, und weil die zu wenig sagen, sich die Begriffe mit "C++ von A bis Z" beibringen zu wollen.
Also es tut mir leid, aber ich hab echt das Gefühl, dass ihr "neuen" Benutzern hier im Board gar keine Möglichkeit geben wollt, weiter zu helfen bzw. überhaupt zu helfen.
Woher soll ich denn wissen, was Attribute, Objekte usw. sind wenn meiner Meinung nach die Folien und die Vorlesung grottig sind und das mittlerweile zweite Buch für C++ jetzt anscheinend wieder nix taugt?
Ich weiß nicht aber anscheinend bin ich ja in letzter Zeit zu blöd für alles, wenn ich nach speziell diesem Board hier gehe...
Ihr seid auf bestem Weg einen Benutzer zu vergraulen; aber das dürfte euch ja egal sein nicht wahr?
-
Wenn es dir darum geht, sauberes C++ zu lernen und nicht nur die nächste Klausur zu bestehen, dann kann ich dir persönlich den C++ Primer empfehlen. In den FAQ findeste aber noch weitere Buchempfehlungen. Und Bücher hast du dringend nötig
-
Dudemeister schrieb:
Versuch doch mal ne Klasse Auto zu schreiben, die einen Kilometerstand hat. Nun soll es möglich sein verschiedene Autos anzulegen, z.B. ein Neues mit Kilometerstand = 0, oder ein gebrauchtes mit beliebigem Kilometerstand.
Ich nenne also die Klasse Automobil. Was ich dann aber nicht merh verstehe, ist, warum die Klasse einen Kilometerstand hat. Muss ich den Kilometerstand durch über eine Methode von "außen" übergeben? Oder wie stellst du dir das vor?
-
Naja, ein Auto hat meistens nen Kilometerstand. Nicht über eine Methode, der Kilometerstand soll im Konstruktor übergeben werden.
So dass man schreiben kann:
Automobil gebrauchtWagen(2000); Automobil neuWagen(0);
Aber du solltest dir Konstruktoren allgemein nochmal anschauen. Such einfach Beispiele oder Tutorials im Netz.
-
Also, das hier sollte doch jetzt schon mal gar nicht mehr so schlecht sein, oder?
#include<iostream> using namespace std; class Automobil { private: public: Automobil() //Konstruktor { } }; int main() { Automobil gebraucht(20000), neu(0); //im Argument steht der Kilometerstand return 0; }
Konstruktoren tragen anscheinend den gleichen Namen wie die Klasse selbst und haben keinen Rückgabetyp. So viel hab ich schon mal selbst herausgefunden. Was dieser Konstruktor nun aber in diesem konkreten Fall machen soll ist mir schleierhaft...
-
Die Parameter des Konstruktors und die beim Aufruf übergebenen Argumente müssen natürlich zusammenpassen.
Aber ich weiss nicht ob das hier viel bringt, du solltest dir wirklich in Ruhe die Thematik durchlesen, dann musst du auch nicht andauernd grundlegendste Dinge fragen.
-
vip@r schrieb:
Also, das hier sollte doch jetzt schon mal gar nicht mehr so schlecht sein, oder?
Naja, stell dir folgendes vor:
Ich du bist Autohändler und willst deine Autos jetzt im Programm darstellen. Ein Auto hat für dich folgende wichtige Eigenschaften:
Farbe, Zählerstand, KaputtDann könntest du das so verwenden wollen:
Auto deinAuto(1000, "Rot", false); //1000 km Zählerstand //Farbe ist Rot //Kaputt ist false, also nicht Kaputt Auto meinAuto(0, "Schwarz", false); cout<<"Mein Auto ist "<<meinAuto.getFarbe()<<" lackiert\n"; cout<<"Dein Auto ist "<<deinAuto.getFarbe()<<" lackiert\n"; fahrOffRoad(meinAuto); fahrOffRoad(deinAuto); //Funktion die mit x Prozentiger Wahrscheinlichkeit das Auto kaputt macht //und den Zählerstand um y Kilometer erhöht if(deinAuto.isKaputt()) { cout<<"Dein Auto ist Kaputt gegangen :)\n"; } if(meinAuto.istKaputt()) { cout<<"Mein Auto ist Kaputt genagen :(\n"; } cout<<"Die Zählerstande lauten:\n"; cout<<"Mein Auto: "<<meinAuto.getZaehlerstand()<<" km\n"; cout<<"Dein Auto: "<<deinAuto.getZaehlerstand()<<" km\n";
Und dazu jetzt die Funktion fahreOffRoad() schreiben und die Klasse Auto implementieren. Das ist eine nette Übung
-
Hab die Übung mal ausprobiert, Shade of Mine. Bei mir funktionierts. Ob's toll programmiert ist, weiß ich nicht:
#include<iostream> #include<ctime> using namespace std; class Auto { private: char wagenfarbe[10]; public: int kilometerstand; bool wagenstatus; Auto(int zaehlerstand, char farbe[10], bool status) { kilometerstand = zaehlerstand; for(int i=0; i<10; i++) { wagenfarbe[i] = farbe[i]; } wagenstatus = status; } char *getFarbe() { return wagenfarbe; } bool istKaputt() { return wagenstatus; } int getZaehlerstand() { return kilometerstand; } }; Auto fahrOffRoad(Auto automobil) { int prozent, zaehlerstand_erhoehung, zaehlerstand; srand(time(NULL)); prozent = rand() % 100 + 1; if(prozent > 50) { automobil.wagenstatus = true; } srand(time(NULL)); zaehlerstand_erhoehung = rand() % 100 + 1; automobil.kilometerstand = automobil.kilometerstand + zaehlerstand_erhoehung; return automobil; } int main() { Auto deinAuto(1000, "Rot", false); //1000 km Zählerstand //Farbe ist Rot //Kaputt ist false, also nicht Kaputt (wenn false, dann Auto nicht kaputt) Auto meinAuto(0, "Schwarz", false); cout << "Mein Auto ist " << meinAuto.getFarbe() << " lackiert\n"; cout << "Dein Auto ist " << deinAuto.getFarbe() << " lackiert\n"; //Funktion die mit x Prozentiger Wahrscheinlichkeit das Auto kaputt macht //und den Zählerstand um y Kilometer erhöht meinAuto = fahrOffRoad(meinAuto); deinAuto = fahrOffRoad(deinAuto); if(deinAuto.istKaputt()) { cout << "Dein Auto ist Kaputt gegangen :)\n"; } if(meinAuto.istKaputt()) { cout << "Mein Auto ist Kaputt gegangen :(\n"; } cout<< "Die Zaehlerstaende lauten:\n"; cout<< "Mein Auto: " << meinAuto.getZaehlerstand() << " km\n"; cout<< "Dein Auto: " << deinAuto.getZaehlerstand() << " km\n"; return 0; }
-
Mir fällt grad was ganz komisches auf. Wenn ich das Programm schrittweise durchdebugge, dann bekomm ich für die Kilometerzahlen unterschiedliche Werte; wenn ich das Programm aber selbstständig bis zum Ende laufen lasse, dann hab ich beim Wert für zaehlerstand_erhoehung und automobil.wagenstatus (somit respektive "prozent") jeweils die gleichen Werte.
Und das ist immer so der Fall!
Könnt ihr mir sagen was das soll?
-
Der Ansatz ist schon gut, aber:
- Member-Variablen sollten privat sein und nur über Methoden der Klasse geändert werden
- für wagenfarbe hätte ich einen std::string verwendet, für wagenstatus einen enum (oder einen anderen Namen)
- die Parameter-Übergabe und Rückgabe hat etwas Java-artigesPS: Was die Zufallswerte angeht: srand() ruft man nur einmal au, nicht vor jeder Zuallszahl.
-
CStoll schrieb:
Der Ansatz ist schon gut, aber:
- Member-Variablen sollten privat sein und nur über Methoden der Klasse geändert werdenIch hab jetzt mal zwei neue Methoden eingefügt; changeWagenstatus und changeKilometerstand.
CStoll schrieb:
- für wagenfarbe hätte ich einen std::string verwendet, für wagenstatus einen enum (oder einen anderen Namen)
Ich bin das noch so aus C gewohnt; sorry...
CStoll schrieb:
- die Parameter-Übergabe und Rückgabe hat etwas Java-artiges
Was meinst du damit? Ich kenn Java nicht...
CStoll schrieb:
PS: Was die Zufallswerte angeht: srand() ruft man nur einmal au, nicht vor jeder Zuallszahl.
srand hab ich jetzt nur einmal drin!
Hier mein neuer Code:
#include<iostream> #include<ctime> #include<string> using namespace std; class Auto { private: string wagenfarbe; int kilometerstand; bool wagenstatus; public: Auto(int zaehlerstand, string farbe, bool status) { kilometerstand = zaehlerstand; wagenfarbe = farbe; wagenstatus = status; } string getFarbe() { return wagenfarbe; } bool istKaputt() { return wagenstatus; } int getZaehlerstand() { return kilometerstand; } int changeKilometerstand(int zaehlerstand) { kilometerstand = zaehlerstand; return kilometerstand; } int changeWagenstatus(bool status) { wagenstatus = status; return wagenstatus; } }; Auto fahrOffRoad(Auto automobil) { int prozent, zaehlerstand_erhoehung, zaehlerstand; srand(time(NULL)); prozent = rand() % 100 + 1; if(prozent > 50) { automobil.changeWagenstatus(true); } zaehlerstand_erhoehung = rand() % 100 + 1; automobil.changeKilometerstand(zaehlerstand_erhoehung + automobil.getZaehlerstand()); return automobil; } int main() { Auto deinAuto(1000, "Rot", false); //1000 km Zählerstand //Farbe ist Rot //Kaputt ist false, also nicht Kaputt (wenn false, dann Auto nicht kaputt) Auto meinAuto(0, "Schwarz", false); cout << "Mein Auto ist " << meinAuto.getFarbe() << " lackiert\n"; cout << "Dein Auto ist " << deinAuto.getFarbe() << " lackiert\n"; //Funktion die mit x Prozentiger Wahrscheinlichkeit das Auto kaputt macht //und den Zählerstand um y Kilometer erhöht meinAuto = fahrOffRoad(meinAuto); deinAuto = fahrOffRoad(deinAuto); if(deinAuto.istKaputt()) { cout << "Dein Auto ist Kaputt gegangen :)\n"; } if(meinAuto.istKaputt()) { cout << "Mein Auto ist Kaputt gegangen :(\n"; } cout<< "Die Zaehlerstaende lauten:\n"; cout<< "Mein Auto: " << meinAuto.getZaehlerstand() << " km\n"; cout<< "Dein Auto: " << deinAuto.getZaehlerstand() << " km\n"; return 0; }
Das Problem, welches ich vorhin geschildert habe, dass die Werte nur unterschiedlich sind, wenn ich das Programm schritweise durchmach, besteht immer noch. Ich verstehe das überhaupt nicht!
-
Ich hab jetzt mal zwei neue Methoden eingefügt; changeWagenstatus und changeKilometerstand.
Ich hätte da eher Funktionen erzeugt, die das ausdrücken was mit dem Wagen passieren soll:
void fahre(int strecke);
bzw.void beschaedige();
/void repariere();
vip@r schrieb:
CStoll schrieb:
- für wagenfarbe hätte ich einen std::string verwendet, für wagenstatus einen enum (oder einen anderen Namen)
Ich bin das noch so aus C gewohnt; sorry...
Und dann die manuelle Kopierschleife ohne Rücksicht auf Null-Terminatoren *tststs*
CStoll schrieb:
- die Parameter-Übergabe und Rückgabe hat etwas Java-artiges
Was meinst du damit? Ich kenn Java nicht...
Ich habe mich auch nicht intensiv mit Java beschäftigt, aber dort ist es afair üblich, daß die Objekte unveränderlich sind und bei Bedarf modifizierte Kopien zurückgeben. In C++ kenne ich das eher so, daß man die Objekte per Referenz übergibt und direkt beeinflußt:
void fahrOffRoad(Auto& automobil) { int prozent, zaehlerstand_erhoehung; prozent = rand() % 100 + 1; if(prozent > 50) { automobil.beschaedige(); } zaehlerstand_erhoehung = rand() % 100 + 1; automobil.fahre(zaehlerstand_erhoehung); }
CStoll schrieb:
PS: Was die Zufallswerte angeht: srand() ruft man nur einmal au, nicht vor jeder Zuallszahl.
srand hab ich jetzt nur einmal drin!
Dort wird es immer noch bei jedem Funktionsaufruf ausgeführt. Setz den Aufruf lieber an den Anang der main().
-
Dort wird es immer noch bei jedem Funktionsaufruf ausgeführt.
Du meintest vorhin wohl das rand. Ich hab das srand gemeint; schön aneinander vorbei geredet...
Aber wenn ich das rand an den Anfang der main schreibe, dann wird es ja nur einmal ausgeführt, oder? Ich möchte aber doch für die beiden Aufrufe der Funktion fahrOffRoad() unterschiedliche rand-Werte!
Oder versteh ich da was grad nicht?
Edit: Jetzt hab ich verstanden! Du meintest schon srand... srand soll tatsächlich nur 1x im Programm initialisiert werden! Die Zeit läuft ja weiter
-
vip@r schrieb:
Dort wird es immer noch bei jedem Funktionsaufruf ausgeführt.
Du meintest vorhin wohl das rand. Ich hab das srand gemeint; schön aneinander vorbei geredet...
Ich meinte schon das srand()
Edit: Jetzt hab ich verstanden! Du meintest schon srand... srand soll tatsächlich nur 1x im Programm initialisiert werden! Die Zeit läuft ja weiter
Wenigstens bei einem Thema ist der Groschen gefallen
-
Hey Leute!
Kann vielleicht nochmal jemand eine ähnliche "Übungsaufgabe" posten? Hat ja das letzte Mal recht geklappt. Würd mich freun!
Ich hab hier mal eine Klasse schreiben wollen, die einen komplexen Datentyp zur Verfügung stellt. Hat aber nicht so ganz geklappt:
#include<iostream> using namespace std; class data_komplex { private: struct komplex { int real; int imag; }; public: data_komplex(komplex data) { data.imag = 0; data.real = 0; } }; int main() { data_komplex data; data_komplex(data); return 0; }
-
Hm, der Lernerfolg war wohl ... sagen wir mal bescheiden
Um auf deinen zuletzt geposteten code einzugehen:
Es gibt mehrere Fehler, die du allerdings eigentlich alle selber lösen können solltest bzw. erkennen solltest.
Deine Aussage "Hat aber nicht so ganz geklappt" heisst wohl schlicht und einfach: compiliert nicht.Allerdings wird dein compiler dir sicherlich Fehlermeldungen präsentiert haben. Du solltest anfangen, diese zu lesen und vorallem auch zu verstehen.
Vermutlich wird er erstmal meckern, dass kein Standardkonstruktor für die Klasse data_komplex vorhanden ist.
Jetzt solltest du dir erstens überlegen, warum er überhaupt einen Standardkonstruktor erwartet, warum er keinen bereitstellt und dann schaust du dir deine Klasse an und überlegst, was für einen Konstruktor du tatsächlich hast.Nächster Schritt ist zu überlegen, wie man also ein data_komplex-Objekt erzeugt mit dem vorhandenen Konstruktor. Wenn du das versuchst, wirst du auf den nächsten Fehler stossen bzw. der compiler wird wieder meckern. Aber eins nach dem anderen.
-
Ich hab hier dann mal nochmal was verändert. Jetzt funktioniert das soweit.
#include<iostream> using namespace std; class komplex { private: int real; int imag; public: komplex() //Konstruktor { real = 0; imag = 0; } ~komplex() //Destruktor; was könnte der hier für eine Funktion haben? { } void changeKomplex() { cout << "Neuer Realteil: " ; cin >> real; cout << "Neuer Imaginärteil: "; cin >> imag; } void getReal_Imag(komplex &zahl) { cout << zahl.real << "+" << imag << "i" << endl; } }; void showKomplex(komplex zahl) { zahl.getReal_Imag(zahl); } int main() { komplex data1, data2; //Klassendeklaration data1.changeKomplex(); data2.changeKomplex(); showKomplex(data1); showKomplex(data2); return 0; }
Ich frage mich nun nur schon die ganze Zeit, was der Destruktor in diesem Fall macht? Könnt ihr mir helfen? Ist das Programm soweit ok?
-
Ich wusste gar nicht, dass man bei einer so primitiven Klasse so viel falsch machen kann.
-
314...
Meinst du meinen neuen oder den alten Code?
-
vip@r schrieb:
Ich hab hier mal eine Klasse schreiben wollen, die einen komplexen Datentyp zur Verfügung stellt.
Es wirkt auf mich so, als wuerdest du versuchen eine Klasse zu schreiben ohne zu wissen was du genau damit machen willst. Meine "Aufgabe" vorhin ist den anderen Weg gegangen: ich habe ein Ziel und dort will ich hin. Die Klasse ist der Weg dorthin. Wenn du nun kein Ziel hast, dann wird die Klasse schwammig. Dann tust du dir schwer die Klasse richtig zu implementieren weil du selber nicht genau weisst was du tun sollst. Das Auto Beispiel war zB bis auf das srand (was ja mit der Klasse ansich nichts zu tun hat) ordentlich. Dein Komplex hier ist leider garnichts.
Also definiere dir eine Aufgabenstellung:
Schreib ein Programm, dass 2 Brueche einliest und diese dann miteinander multipliziert, dividiert, subtrahiert und addiert. Und gib alle 4 Ergebnisse in Bruchform aus. bzw. kannst du das natuerlich auch mit komplexen Zahlen statt Bruechen machen wenn du in der Mathematik fit genug bist.
Im Prinzip spielt es keine grosse Rolle was du als Ziel definierst. Die Klasse ist dann der Weg dorthin. uU brauchst du auch mal mehrere Klassen. Aber wichtig ist: ein klares Ziel.