[Aufgabe] Klasse - Zeit
-
Hallo,
Zuerst möchte ich euch allen ein frohes neues Jahr wünschen, hoffe ihr seit gut reingerutscht.Zum anfang des Jahres habe ich mir eine nächste Aufgabe geschnappt und möchte diese gerne mit eurer Unterstützung lösen ( ich bitte euch das ihr mir jeweils nur etwas auf die Sprünge helft, also bitte keine Komplettlösung)
Habe mich auch schon etwas über Klassen informiert ( auch in Vorlesung hatten wir das angeschnitten), doch noch nichts damit programmiert.
Folgende Aufgabe möchte ich bearbeiten:
Aufgabe: Klasse - Zeit
a) Definieren Sie eine Klasse zeit, die als Datenelemente die int-Varibalen
stunde und minute besitzt.
Die Klasse soll einen Standard-Konstruktor und einen Parameter-Konstruktor
(2 Parameter, der erste für die Stunde, der zweite für die Minute. Im Konstruktor soll die Zeitangabe normiert werden, so dass die Minuten < 60 sind,
d. h. aus 3 Stunden und 83 Minuten soll normiert werden in 4 Stunden und 23 Minuten.) haben.Ferner enthält sie die Methoden getstunde, getminute und getstundedezimal, die die Zeit in Stunden als Dezimalwert liefert.
(Beispiel: 2 Stunden und 45 Minuten ergeben als StundeDezimal: 2.75)
Zum Addieren von zwei Zeiten soll der +-Operator überladen werden,
der Ausgabeoperator ( << ) soll über eine friend-Funktion überladen werden und Stunde, Minute und StundeDezimal ausgeben.
(Beispiel: 2 Stunden und 45 Minuten ergeben als StundeDezimal: 2.75)b) Definieren Sie die Konstruktoren und die Methoden und überladene Operatoren von a).
c) Schreiben Sie dazu eine main-Funktion, in der die Objekte zeit1 (initialisiert mit 3 Stunden und 83 Minuten), zeit2 (initialisiert mit 1 Stunde und 52 Minuten) und zeitsumme (nicht initialisiert) definiert werden. Danach soll zeitsumme den Wert von zeit1 + zeit2 erhalten. Für zeitsumme sollen die Stunden, die Minuten und der Gleitkommawert der Stunden ausgegeben werden.
Hier mein Lösungsansatz:
#include <iostream> using namespace std; int main() { //a) Klasse erstellen class Zeit { public: int stunde,minute; Zeit(); //Standard-Konstruktor Zeit(int h, int min); //Parameter-Konstruktor //h - Stunde, min - Minute //-> da prototyp sind parameternamen erstmal egal oder? //Methoden Prototypen getstunde(); getminute(); getstundedezimal(int h, int min); }
So bis hierher,
Fragen dazu:
- gibt es eine Funktion in der Libary die das normieren übernehmen kann?
- Mit dem überladen des + Operators ist inkrementieren gemeint oder? ( also entweder als prefix oder postfix)
- Wie ich den << Operator über eine Friendfunktion überlade habe ich absolut keine Ahnungsoviel erstmal zur a)
vielen dank im voraus, und ich wünsch euch ein gesegnetes Jahr 2008 und auserdem noch einen schönen Feiertag.
mfg fraggelfragger
-
hi & happy NY!
zunächst zu deinem code
fraggelfragger schrieb:
#include <iostream> using namespace std; int main() { //es ist zwar möglich, klassen innerhalb von funktionen //zu definieren, allerdings nur selten angebracht. //kann später mal probleme machen, also lieber im regelfall //außerhalb definieren. class Zeit { public: int stunde,minute; //wenn man sowieso auf stunde und minute //zugreifen kann, warum dann die get*-methoden? Zeit(); Zeit(int h, int min); getstunde(); //was gibt getstunde zurück? ein int wahrscheinlich getminute(); //dito getstundedezimal(int h, int min); //ich glaube, getstundedezimal //soll den _eigenen_ zeitwert liefern. also folgende deklaration verwenden: double getstundedezimal (); }; //nicht das ";" vergessen!
du vergisst bei deinen funktionen, einen rückgabetyp anzugeben. membervariablen sollten private in der klasse sein, nicht public (ist ja immerhin der sinn der datenkapselung)
- gibt es eine Funktion in der Libary die das normieren übernehmen kann?
ja, die division und den modulo-operator. ist aber deine eigene aufgabe, das normieren zu implementieren
hinweis: minuten / 60 und minuten % 60.- Mit dem überladen des + Operators ist inkrementieren gemeint oder? ( also entweder als prefix oder postfix)
mit dem überladen von operator+ ist gemeint, dass folgendes konstrukt (aufgabe c) funktioniert:
Zeit a, b, c; a = b + c; //hier wird operator+ verwendet
- Wie ich den << Operator über eine Friendfunktion überlade habe ich absolut keine Ahnung
nicht "über" sondern "als":
class Zeit { //... friend ostream& operator << (ostream& out, Zeit const& time); }; ostream& operator << (ostream& out, Zeit const& time) { return out << time.stunde << "h " << time.minute << "m = " << time.getstundedezimal(); //besser ohne friend und so: //return out << time.getstunde() << "h " << time.getminute() << "m = " time.getstundedezimal(); //siehe auch den nachtrag }
allerdings ist es hier überflüssig, den operator zum friend zu machen, immerhin hat die klasse ein schönes öffentliches interface (getstunde, getminute), das der operator<< verwenden könnte.
noch ein kleiner nachtrag zur const-correctness: die get*-methoden verändern nichts am internen status der klasse, deshalb wäre es nur richtig (und notwendig), sie als const zu deklarieren:
class Zeit { //... int getstunde () const; //... };
das ist eine zusicherung, die dem compiler sagt, dass die verwendung der methode gestunde keinerlei veränderung an den interna vornehmen wird und notwendig, sobald du über eine konstante referenz (die z.b. oben bei operator<< verwendet wird) auf die methode zugreifen willst.
-
Es ist wohl einfacher einfach nur die Sekunden zu speichern. Dann kannst du einfacher zwei Zeitspannen addieren, und die Ausgabe ist auch nicht schwer:
Stunden := MinutenGesamt / 60
Minuten := MinutenGesamt % 60
StundenDez := MinutenGesamt / 60**.**
-
#include <iostream> using namespace std; //a) Klasse erstellen class Zeit { public: Zeit(); //Standard-Konstruktor Zeit(int Stunde, int Minute); //Parameter-Konstruktor const int getstunde(); const int getminute(); const double getstundedezimal(); //b) int Zeit::getstunde(int Stunde,int Minute) { Stunde += Minute/60; return Stunde; } int Zeit::getminute(int Stunde,int Minute) { Minute = Minute%60; return Minute; } double Zeit::getstundedezimal (int Stunde,int Minute) { int MinutenGesamt=0; double stundendezimal; MinutenGesamt = Minute + Stunde*60; stundendezimal = double(MinutenGesamt)/60; return stundendezimal; } }; //b) Methode zum addieren zweier Zeiten int zeitsumme(int a,int b); int main() { //c) int zeit1 = Zeit::Zeit(3,83);; int zeit2 = Zeit::Zeit(1,52);; int var_zeitnumme = zeitsumme(zeit1,zeit2); Zeit::Zeit(0,var_zeitsumme);; system("pause"); return 0; } Zeit::Zeit(int Stunde,int Minute) { int var_getstunde = Zeit::getstunde(Stunde,Minute);; int var_getminute = Zeit::getminute(Stunde,Minute);; double var_getstundedezimal = Zeit::getstundedezimal (Stunde,Minute);; int var_MinutenGesamt = var_getstunde*60 + var_getminute; cout << var_getstunde << endl; cout << var_getminute << endl; cout << var_getstundedezimal << endl; return var_MinutenGesamt; } int zeitsumme(int a,int b) { int c = a + b; return c; }
so richtig bisher?
Jemand mit mehr Ahnung schrieb:
Es ist wohl einfacher einfach nur die Sekunden zu speichern. Dann kannst du einfacher zwei Zeitspannen addieren, und die Ausgabe ist auch nicht schwer:
Stunden := MinutenGesamt / 60
Minuten := MinutenGesamt % 60
StundenDez := MinutenGesamt / 60**.**ja aber ist das nicht durch die aufgabenstellung so vorgeschrieben?
//edit 1 : neuer stand eingefügt
//edit 2 : neues Update
-
//c) int zeit1 = Zeit::Zeit(3,83);; int zeit2 = Zeit::Zeit(1,52);; zeitsumme(zeit1,zeit2);
hierfür kommt ein compiler Fehler:
error C2440: 'Initialisierung': 'Zeit' kann nicht in 'int' konvertiert werden
blos wie kann ich diesen Fehler beseitigen?
mfg
//edit
ahhhh... ich habs glaub rausgefunden, der Kontruktor darf keinen Rückgabewert haben. Deshalb zeigt er da Fehler an.
//edit 2: Jetzt ist eigentlich nur noch das Problem da wie ich aus der Klasse Zeit das getminute und getstunde zusammen in eine zeit1 variable verpacke.
Dazu werd ich mir nochma genauer das was queer_boy geschrieben hat anschauen.//edit 3: Ich hab mir das jetzt nochma angeschaut aber ich verstehe es nicht.
queer_boy wo schreibe ich den unteren Teil rein? in die Main Methode? oder unterhalb der Main Methode?diese Friend Funktion soll also die Unterfunktionen in der Klasse von aussen benutzbar machen?! Aber da das ja sowiso Public ist kann man es in diesem Fall einfacher machen.
Ich verstehe leider beide Möglichkeiten nicht wie ich sie einbinden kann.
#include <iostream> using namespace std; //a) Klasse erstellen class Zeit { public: Zeit(); //Standard-Konstruktor Zeit(int Stunde, int Minute); //Parameter-Konstruktor const int getstunde(); const int getminute(); const double getstundedezimal(); //b) int Zeit::getstunde(int Stunde,int Minute) { Stunde += Minute/60; return Stunde; } int Zeit::getminute(int Minute) { Minute = Minute%60; return Minute; } double Zeit::getstundedezimal (int Stunde,int Minute) { int MinutenGesamt=0; double stundendezimal; MinutenGesamt = Minute + Stunde*60; stundendezimal = double(MinutenGesamt)/60; return stundendezimal; } }; //b) Methode zum addieren zweier Zeiten int zeitsumme(int a,int b); int main() { Zeit::Zeit(3,83); Zeit::Zeit(1,52); int zeit1=Zeit::getminute(83) + Zeit::getstunde(3)*60; int zeit1=Zeit::getminute(52) + Zeit::getstunde(1)*60; zeitsumme(int a,int b); system("pause"); return 0; } Zeit::Zeit(int Stunde,int Minute) { cout << Zeit::getstunde(Stunde,Minute);; cout << "\t" ; cout << Zeit::getminute(Stunde,Minute);; cout << "\t" ; cout << Zeit::getstundedezimal (Stunde,Minute);; cout << "\t" ; cout << endl; } int zeitsumme(int a,int b) { int c = a + b; return c; }
-
ok ok, das schreit nach einer etwas ausführlicheren erklärung. zunächst die aufgabenstellung:
Aufgabe: Klasse - Zeit
a) Definieren Sie eine Klasse zeit, die als Datenelemente die int-Varibalen
stunde und minute besitzt.
Die Klasse soll einen Standard-Konstruktor und einen Parameter-Konstruktor
(2 Parameter, der erste für die Stunde, der zweite für die Minute. Im Konstruktor soll die Zeitangabe normiert werden, so dass die Minuten < 60 sind,
d. h. aus 3 Stunden und 83 Minuten soll normiert werden in 4 Stunden und 23 Minuten.) haben.Ferner enthält sie die Methoden getstunde, getminute und getstundedezimal, die die Zeit in Stunden als Dezimalwert liefert.
(Beispiel: 2 Stunden und 45 Minuten ergeben als StundeDezimal: 2.75)
Zum Addieren von zwei Zeiten soll der +-Operator überladen werden,
der Ausgabeoperator ( << ) soll über eine friend-Funktion überladen werden und Stunde, Minute und StundeDezimal ausgeben.
(Beispiel: 2 Stunden und 45 Minuten ergeben als StundeDezimal: 2.75)b) Definieren Sie die Konstruktoren und die Methoden und überladene Operatoren von a).
c) Schreiben Sie dazu eine main-Funktion, in der die Objekte zeit1 (initialisiert mit 3 Stunden und 83 Minuten), zeit2 (initialisiert mit 1 Stunde und 52 Minuten) und zeitsumme (nicht initialisiert) definiert werden. Danach soll zeitsumme den Wert von zeit1 + zeit2 erhalten. Für zeitsumme sollen die Stunden, die Minuten und der Gleitkommawert der Stunden ausgegeben werden.
auf deutsch: a) verlangt ist eine klassendefinition, d.h. ein konstrukt in der art
class Zeit { //... };
soweit so gut.
b) verlangt die definitionen der elementmethoden. die musst du außerhalb der klasse definieren (so interpretiere ich die aufgabenstellung)
beispiel://klassendefinition class Foo { public: void bar (); }; //funktionsdefinition außerhalb der klasse void Foo::bar () { }
was du machst (oder versuchst zu tun), ist die funktionsdefinitionen in die klasse hineinzupacken. das ist zwar möglich, funktioniert aber nicht so, wie du versucht hast. so wäre es richtig:
//klassendefinition class Zeit { public: //sogenannte "inline"-definition der elementmethode "getstunde" int getstunde () const { return stunde; } //... };
so, aufgabenstellung teil 3 (c), ich hoffe, wenn ich dir den erkläre, verstehst du mehr. die aufgabe ist, drei objekte zu erstellen (die heißen sollen: zeit1, zeit2 und zeitsumme) und zwar drei objekte vom typ "Zeit".
wie erstellt man objekte vom typ Zeit? (richtigsprech: wie instanziiert man die klasse Zeit?)
nun, wie erstellt man objekte vom typ int? so:int main () { int x; //definition von x int y = 5; //definition & initialisierung von y int z(5); //definition & initialisierung von z - äquivalent zu y. }
wie also erstellt man objekte vom typ Zeit? so:
int main () { Zeit zeit1; //initialisierte mithilfe des standardkonstruktors Zeit zeit2; //dito Zeit zeitsumme; //dito }
aufgabe (c) geht aber weiter: sie verlangt, dass zeit1 und zeit2 mit bestimmten werden initialisiert werden müssen. also so:
int main () { Zeit zeit1(3, 83); //oder mit dem "=" analog zu oben: Zeit zeit2 = Zeit(1, 52); //ist äquivalent zur definition von zeit1 Zeit zeitsumme; //zeitsumme soll vom standardkonstruktor initialisiert werden (laut aufgabe) }
aufgabe (c) geht aber immer noch weiter: in zeitsumme soll die summe von zeit1 und zeit2 gespeichert werden. wie berechnet man die summe von zeit1 und zeit2? man schreibt eine funktion:
Zeit summiere_zeiten (Zeit const& a, Zeit const& b) { return Zeit(a.getstunde() + b.getstunde(), a.getminute() + b.getminute()); } //verwendung: int main () { Zeit zeit1 (3, 83); Zeit zeit2 (1, 52); Zeit zeitsumme = summiere_zeiten (zeit1, zeit2); }
wie würde das mit int funktionieren? also wie würdest du zwei zahlen addieren? doch wohl so:
int main () { int a = 30; int b = 12; int c = a + b; }
es wäre doch praktisch, denselben code auch verwenden zu können, wenn a, b und c objekte vom typ Zeit wären, nicht? folgendes funktioniert aber nicht (von sich aus):
int main () { Zeit zeit1(3,83); Zeit zeit2(1,52); Zeit zeitsumme = zeit1 + zeit2; }
der compiler kann ja nicht von selbst draufkommen, wie er die summe von zwei zeiten berechnen soll, sonst hätten wir ja nicht die funktion summiere_zeiten schreiben müssen.
das stichwort jetzt ist operatorenüberladung: wir definieren einen eigenen operator+, der sich für objekte vom typ Zeit so verhält, wie der eingebaute operator+ für int.das funktioniert so:
class Zeit { //... }; Zeit operator+ (Zeit const& a, Zeit const& b) { return Zeit(a.getstunde() + b.getstunde(), a.getminute() + b.getminute()); } //eigentlich würde man den operator+ anders implementieren, //nämlich über den operator+=, aber das ist uns jetzt egal. int main () { //... Zeit zeitsumme; zeitsumme = zeit1 + zeit2; }
@fraggelfragger:
du scheinst noch ein bisschen im unklaren über den unterschied zwischen klasse und instanz zu sein. ich weiß daher nicht, ob es sinnvoll ist, schon über operatorenüberladung zu reden (anscheinend kennst du dich damit nicht ganz aus)auf jedenfall soll folgender code (aufgabenstellung (c)) am ende funktionieren:
int main () { Zeit zeit1(3, 83); Zeit zeit2(1, 52); Zeit zeitsumme; zeitsumme = zeit1 + zeit2; cout << zeitsumme << '\n'; }
das ist, was unter (c) gefordert ist. jetzt nur noch das rundherum programmieren.
ich gebe dir nen tipp: die klassendefinition sieht korrekterweise (nach aufgabenstellung) so aus:class Zeit { private: int stunde, minute; public: Zeit (); Zeit (int stunde, int minute); int getstunde () const; //das const _nach_ die funktionsklammern int getminute () const; double getstundedezimal () const; }; //und die implementation der methoden _außerhalb_ der klasse so: int Zeit::getstunde () const { return stunde; } //usw.
ja, das friend kannst du dir übrigens sparen, wenn du stunde und minute public machst. aber das verletzt das prinzip der datenkapselung. dann bräuchtest du ja erst keine klassen.
bezüglich der operatorenüberladung hab ich eh schon einiges gesagt. frag nach, was noch unklar ist.
-
wow das ist ja super Klasse!, ich bedanke mich erstmal für deine ausführliche Erklärung.
Glaube das bringt mich um ein ganzes Stück weiter.ich werd mir das anschauen und alles nachvollziehen, fals dann noch fragen offen sind werde ich fragen.
queer_boy schrieb:
@fraggelfragger:
du scheinst noch ein bisschen im unklaren über den unterschied zwischen klasse und instanz zu sein. ich weiß daher nicht, ob es sinnvoll ist, schon über operatorenüberladung zu reden (anscheinend kennst du dich damit nicht ganz aus)ja da hast du nicht ganz unrecht, ich werde mich darüber informieren.
vielen dank nochmal, ich wünsche noch einen schönen Abend
mfg fraggelfragger
-
Guten Tag,
Ich habe das Programm nun soweit fertig,
doch an dieser Stelle ist momentan glaube ich noch etwas falsch:
Zeit::Zeit(int stunde, int minute) { getstunde (); //warum kann ich hier jetzt keine 2 Argumente übergeben? getminute (); //somit kann ich die richtige Stundeanzahl usw. ja nicht bestimmen getstundedezimal (); }
eine Frage noch dazu:
int getstunde () const;
das const bedeutet hier ja nur das der Rückgabewert der Funktion const ist oder?
die übergebenen Werte ( z.b minute oder stunde ) sind dann nicht const und dürfen innerhalb der Funktion verändert werden (auserhalb bleiben diese so wie sie waren)#include <iostream> using namespace std; //a) Klasse erstellen class Zeit { private: int stunde, minute; public: Zeit (); Zeit (int stunde, int minute); //Prototypen int getstunde () const; int getminute () const; double getstundedezimal () const; friend ostream& operator << (ostream& out, Zeit const& time); }; //b) Definieren der Methoden und deklarieren der überladene Operatoren int Zeit::getstunde()const { int var_stunde = stunde + minute/60; return stunde; } int Zeit::getminute()const { int var_minute = minute%60; return minute; } double Zeit::getstundedezimal () const { int minutengesamt=0; double stundendezimal; minutengesamt = minute + stunde*60; stundendezimal = double(minutengesamt)/60; return stundendezimal; } Zeit::Zeit() { getstunde (); getminute (); getstundedezimal (); } Zeit::Zeit(int stunde, int minute) { getstunde (); //warum kann ich hier jetzt keine 2 Argumente übergeben? getminute (); //somit kann ich die richtige Stundeanzahl usw. ja nicht bestimmen getstundedezimal (); } //Operatoren Prototype //Optional //Zeit summiere_zeiten (Zeit const& a, Zeit const& b); //wie in Aufgabe verlangt Zeit operator+ (Zeit const& a, Zeit const& b); int main() { //Variablen vom Typ Zeit definieren Zeit zeit1 = Zeit(3, 83); Zeit zeit2 (1, 52); Zeit zeitsumme; zeitsumme = zeit1 + zeit2; //Optional //zeitsumme = summiere_zeiten (zeit1, zeit2); //Ausgabe cout << zeitsumme << '\n'; system("pause"); return 0; } //Operatoren Definition für Klasse Zeit //Optional /*Zeit summiere_zeiten (Zeit const& a, Zeit const& b) { return Zeit(a.getstunde() + b.getstunde(), a.getminute() + b.getminute()); }*/ //wie in Aufgabe verlangt Zeit operator+ (Zeit const& a, Zeit const& b) { return Zeit(a.getstunde() + b.getstunde(), a.getminute() + b.getminute()); } ostream& operator << (ostream& out, Zeit const& time) { //Optional //return out << time.getstunde() << "h " << time.getminute() << "m = " << time.getstundedezimal(); //wie in Aufgabe verlangt return out << time.stunde << "h " << time.minute << "m = " << time.getstundedezimal(); }
-
Im sog. Default-Konstruktor:
Zeit::Zeit()
solltest du Standardwerte festsetzen. Deine Funktionsaufrufen sind dort vollkommen falsch!
Zeit::Zeit() { stunden = 0; minuten = 0; }
. Dann soll im Parameter-Konstruktor stunden und minuten übergeben werden. Im einfachsten Fall (minuten <= 60) wäre das dann einfach:
Zeit::Zeit(int stunden, int minuten) { this->stunden = stunden; this->minuten = minuten; }
Hier siehst du jetzt, dass es sinnvoll ist, bei Membervariablen ein m_ vor dem Namen (Bezeichner) zu setzen, um zu verhinden "this->" schreiben zu müssen.
Da du aber nicht vom idealen Fall ausgehen kannst, d.h. wenn der Wert von "minuten" > 60 ist, musst du dem entsprechend deine Stunden anpassen. Deswegen setzt man ja auch die Membervariablen stunden und minuten als private, damit man solche Fälle abhandeln kann und dem Benutzer keinen direkten zugriff auf die Variablen erlaubt. (Stell dir vor jemand gibt 71 für minuten an und in den restlichen Berechnungen gehst du davon aus, dass es max. 60 sind!)
Zeit::Zeit(int stunden, int minuten) { this->minuten = minuten % 60; this->stunden = this->stunden + (minuten - this->minuten) / 60 }
Der module-operator gibt ja den Rest einer Ganzzahl Division zurück (12 % 5 = 2). Wenn wir jetzt mal annehmen, dass minuten = 128 ist und stunden = 1. Dann würde beim module-operator ja stehen: 128 % 60 = 8. für stunden ergäbe sich dann 1 + (128 -
/ 60. Und das sind, korrekterweise, 3. Dem nach sind 1h und 128min das selbe wie 3h und 8min.
Wenn minuten jetzt <= 60 ist, ergibt sich auch ein korrekter Wert.
minuten = 33;
stunden = 3;
33 % 60 = 33min;
3 + (33 - 33) / 60 = 3h.Damit ist der Konstruktor fertig! (Und ja diesen Vorgang nennt der Autor deiner Aufgabe "Norminierung")
int Zeit::getstunde()const { // int var_stunde = stunde + minute/60; return stunde; }
getstunde() soll einfach nur den Wert der Membervariable stunde zurück geben. Sonst nichts! (minuten / 60 ist hier vollkommen überflüssig, da du die Werte im Konstruktor norminiert hast
d.h. minuten ist < 60)
Auch wenn bsw. 1h und 15 min Dezimal 1.25h wären, wird das bei einer Ganzzahl-Division niemals rauskommen
int Zeit::getminute()const { int var_minute = minute%60; return minute; }
So ist die Funktion murks. Es ist in diesem Fall allerdings die Frage ob nach der Aufgabenstellung die stunden auch in Minuten umgerechnet werden sollen oder einfach nur die Membervariable minuten gewollt ist.
int Zeit::getminute() const { return (stunden * 60 + minuten); }
So wäre es, wenn die Stunden berücksichtigt werden sollen.
int Zeit::getminute() const { return minuten; }
so, wenn nicht
double getstundedezimal () const;
Hier sollst du das erste mal keine Ganzzahl zurück geben. Das ist wichtig!
double Zeit::getstundedezimal () const { int minutengesamt = minute + stunde * 60; double stundendezimal = double(minutengesamt)/60; return stundendezimal; }
Du weißt aber schon, wie Prozentrechnung geht?
http://de.wikipedia.org/wiki/Prozentrechnung nochmal angucken!
Grundwert: 60
Prozentwert: minuten
Prozentsatz: (minuten / 60) * 100
Soweit so gut!double Zeit::getstundedezimal () const { return static_cast<double>(minuten) / 60.0 + stunden; }
static_cast macht in dem Fall aus der Ganzzahl die minuten bezeichnet wird, einen Fließkomma-Typen (double), um dem PC zu sagen, dass hier keine Ganzzahl-Division stattfinden soll, sondern eine Fließkomma-Division.
friend std::ostream& operator << (std::ostream&, Zeit const&);
std::ostream& operator << (std::ostream& out, Zeit const& time) { // return (out << time.stunden << " Stunden und " << time.minuten << " Minuten ergeben als StundeDezimal: " << time.getstundedezimal()); return (out << time.stunden << "h " << time.minuten << "min (" << time.getstundedezimal() << "h)"); }
Das auskommentierte ist so, wie es vom Aufgabensteller erwartet wurde. Sieht allerdings ziemlich doof aus
"2h 45min (2.75h)" sieht besser aus als "2 Stunden und 45 Minuten ergeben als StundeDezimal: 2.75"
Dann musst du jetzt nurnoch operator + überladen!
-
Hmm operator+ vergessen ... okay. Der ist ganz einfach:
friend Zeit operator+(Zeit const& lhs, Zeit const& rhs);
friend Zeit operator+(Zeit const& lhs, Zeit const& rhs) { return Zeit(lhs.m_hour + rhs.m_hour, lhs.m_minutes + rhs.m_minutes); }
Um die Verteilung der minuten auf Stunden kümmert sich ja dein Parameter-Konstruktor, da diese sich ja um die Norminierung kümmert! Also einfach eine neue Instanz erzeugen und fertig
Und dein Beispielprogramm:
#include <iostream> #include "Zeit.hpp" int main() { // Variablen vom Typ Zeit definieren Zeit time_first(3, 83); Zeit time_second(1, 52); // operator + ausprobieren Zeit time = time_first + time_second; // operator << ausprobieren std::cout << "First time: " << time_first << "\nSecond time: " << time_second << "\n=======================\n" << time << std::endl; std::cin.get(); }
Guck mal im F.A.Q. warum std::system("pause") nicht verwendet werden sollte. Also das Beispielprogramm sollte mit deiner Klasse dann problemlos Funktionieren und die Aufgabe sollte fertig sein
-
So, nun bist du ja zu den Klassen fortgeschritten...
Im Konstruktor einer Klasse (der immer denselben Namen wie die Klasse hat) mußt du dafür sorgen, daß das Klassenobjekt richtig initialsiert wird (anhand der Übergabeparameter).
Zeit::Zeit(int stunde, int minute) { this->stunde = stunde; this->minute = minute; }
Da deine internen Klassenvariablen (member) bei dir genau so heißen, wie die Übergabeparameter, muß man zur Unterscheidung noch "this" verwenden (welches implizit auf das eigene Klassenobjekt zeigt).
Alternativ könnte man auch die Übergabeparameter anders benennen.
Eine zweite Möglichkeit der Initialisierung sind Intialisierungslisten:
Zeit::Zeit(int st, int min) : stunde(st), minute(min) // <- Initialisierungsliste { }
So, nachdem das Objekt richtig initialisiert ist, benötigt man jetzt noch Zugriffsfunktionen. Dabei gibt es sogenannte Getter und Setter.
Mit einem Getter kann man Daten auslesen und mit einem Setter Daten setzen.
Da das Auslesen das interne Objekt nicht verändert, kann man die Getter-Methode als konstant deklarieren:
class Zeit { public: ... int getstunde() const; }; int Zeit::getstunde() const { return stunde; }
Dies gibt dem Compiler die Möglichkeit, Fehler zu erkennen und Optimierungen auszuführen.
Ein Setter dagegen soll ja gerade interne Daten (member) verändern, daher darf eine Setter-Methode nicht als konstant deklariert werden, z.B.
void Zeit::setze_zeit(int st, int min) { stunde = st; minute = min; }
Um noch mal zu deinem Konstruktor zurückzukommen: innerhalb des Konstruktors Zeit::Zeit macht es keinen Sinn eine Getter-Methode aufzurufen, da dort ja erst die Member initialisiert werden müssen.
Die Getter und Setter sind für die Anwendung der Klasse wichtig:Zeit zeit(9, 30); // Konstruktor aufrufen cout << zeit.getstunde() << ':' << zeit.getminute(); // Getter aufrufen zeit.setze_zeit(13, 55); // Setter aufrufen cout << zeit; // alternative und bessere Ausgabe mittels des Stream-operators <<
Die Konstantheit der Getter-Funktionen spielt beim Zugriff eine wichtige Rolle.
Wenn du ein konstantes Objekt hast, dann kann man für dieses Objekt auch nur konstante Methoden aufrufen, andernfalls gibt der Compiler einen Fehler aus.const Zeit zeit(0, 0); cout << zeit.getstunde(); // ok zeit.setze_zeit(11, 55); // Fehler, da setze_zeit das Objekt 'zeit' verändern würde
Wenn du nun die Setter-Methode setze_zeit(...) noch so anpaßt, daß sie noch die Zeitnormalisierung durchführt, dann kannst du diese Methode einerseits im Konstruktor noch aufrufen (um das Zeitobjekt gleich richtig zu initialisieren) und andererseits kann man diese Methode auch noch nachträglich aufrufen, um die Zeit neu zu setzen.
Alternativ würde sich hierfür auch der operator = anbieten:const Zeit& Zeit::operator =(const Zeit &zeit) { setze_zeit(zeit.stunde, zeit.minute); return *this; // das geänderte Objekt wieder als (konstante) Referenz zurückgeben // (Dereferenzierung, weil this ein Zeiger ist) } // Aufruf im Hauptprogramm Zeit zeit(10, 20); zeit = Zeit(12, 0); // Zuweisung (operator =)
So, ich hoffe, du bist jetzt nicht vollkommen durcheinander gebracht worden und kommst hiermit ein Stückchen weiter.
-
ahhh... okey so langsam geht mir ein Licht auf.
einige Sachen werd ich erst noch etwas verdauen müssen, aber im Großen und Ganzen ist das jetzt klarer.@ (D)Evil
sicher das es so heissen muss?this->stunden = this->stunden + (minuten - this->minuten) / 60
und nicht so:
this->stunden = stunden + (minuten - this->minuten) / 60
double Zeit::getstundedezimal () const { return static_cast<double>(minuten) / 60.0 + stunden; }
diese Variante sieht sehr elegant aus (werde ich auch in zukunft so machen), aber wäre meine Variante nicht auch gegangen?
double Zeit::getstundedezimal () const { int minutengesamt = minute + stunde * 60; double stundendezimal = double(minutengesamt)/60; return stundendezimal; }
und wozu benötigt man hier Prozentrechnung, soweit ich weis behersche ich eigentlich das Prozentrechnen ich frage mich bloß wo es hier eine Anwendung finden soll?!
Das ist doch hier dreisatz:
60 min - 1 h
90min - x
x = 1h*90min/60min = 1,5hoder stehe ich gerade auf der Pipeline?
System("pause"); werde ich in zukunft nicht mehr nutzen.
Nachteile: - es wird eine Shell geöffnet ( exploits könnten dadurch entstehen)
- es ist ein OS abhängiger Befehl ( je nach OS müssen andere Parameter gesetzt werden.in zukunft werde ich std::cin.get(); verwenden.
Ich danke euch allen recht herzlich für die Geduld und auch dafür das ihr euch die Zeit nehmt einem Anfänger wie mir die Programmiersprache näher zu bringen.
hier nochmal den geänderten Quellcode:
#include <iostream> using namespace std; //a) Klasse erstellen class Zeit { private: int stunde, minute; public: Zeit (); Zeit (int stunde, int minute); //Prototypen int getstunde () const; int getminute () const; double getstundedezimal () const; friend ostream& operator << (ostream& out, Zeit const& time); }; Zeit::Zeit() { stunde = 0; minute = 0; } Zeit::Zeit(int stunde, int minute) { //Normierung this->minute = minute%60; this->stunde = stunde + (minute-this->minute)/60; //oder mit Bezeichner m_ ( brauch man den typ der variablen bei dem Membervariablen bezeichner überhaupt?) //int m_minute = minute%60; //int m_stunde = stunde + (minute-m_minute)/60; } //b) Definieren der Methoden und deklarieren der überladene Operatoren int Zeit::getstunde()const { return stunde; } int Zeit::getminute()const { return minute; } double Zeit::getstundedezimal () const { return static_cast<double>(minute) / 60.0 + stunde; } //Operatoren Prototype //Optional //Zeit summiere_zeiten (Zeit const& a, Zeit const& b); //wie in Aufgabe verlangt Zeit operator+ (Zeit const& a, Zeit const& b); int main() { //Variablen vom Typ Zeit definieren Zeit zeit1 = Zeit(3, 83); Zeit zeit2 (1, 52); Zeit zeitsumme; //Operator + zeitsumme = zeit1 + zeit2; cout << "First time: " << zeit2 << "\nSecond time: " << zeit1 << "\n=======================\n" << zeitsumme << endl; cin.get(); } //Operatoren Definition für Klasse Zeit Zeit operator+ (Zeit const& a, Zeit const& b) { return Zeit(a.getstunde() + b.getstunde(), a.getminute() + b.getminute()); } ostream& operator << (ostream& out, Zeit const& time) { return (out << time.stunde << " Stunden und " << time.minute << " Minuten = " << time.getstundedezimal() << " Stunden (Dezimal)"); }
-
double Zeit::getstundedezimal () const
{
int minutengesamt = minute + stunde * 60;
double stundendezimal = double(minutengesamt)/60;
return stundendezimal;
}Sollte auch gehen ... wobei Function-Style-Cast nicht das Wahre sind.
this->stunden = stunden + (minuten - this->minuten) / 60
Jap hast recht
Tippfehler
operator+ kannst du ruhig als friend setzen ...
Dann guck dir jetzt mal ruhig noch die sog. Initialisierungslisten an und bau das auch ein. Achja und ein Parameter-Konstruktor mit Default-Belegung für alle Parameter kannst du auch als Default-Konstruktor ansehen
Also:
public: Zeit (int stunde = 0, int minute = 0);
Dann kannst du
Zeit();
weglassen.
-
(D)Evil schrieb:
Jap hast recht
Tippfehler
Macht ja nix passiert
Gib doch zu du hast den Fehler extra eingebaut um zu testen ob ich auch aufpasse und nicht nur abtippeSpass bei Seite, das mit der Initialierungsliste werd ich auch gleich mal probieren.
jetzt mach ich aber erstma den operator+ zum friend:
(kleine Zwischenfrage: wenn ich die Klasse in der Zeit.hpp definiere muss ich ja nur in der main.cpp nur #include "Zeit.hpp" schreiben mehr benötige ich nicht oder?) vorrausgesetzt die dateien sind im selben Ordner
So nun mit Freund:
//Datei: Zeit.hpp class Zeit { private: int stunde, minute; public: Zeit (); Zeit (int stunde, int minute); //Prototypen int getstunde () const; int getminute () const; double getstundedezimal () const; friend ostream& operator << (ostream& out, Zeit const& time); friend Zeit operator+ (Zeit const& a, Zeit const& b); //oder //friend Zeit summiere_zeiten (Zeit const& a, Zeit const& b); };
-
Naja also um Linker Fehlern vorzubeugen, da es zu mehrfacher Einbindung der selben Klasse kommen kann, solltest du dir dann Include Guards angucken und evtl. auch #pragma once.
Und using namespace solltest du auch niemals im Header nutzen!
-
double Zeit::getstundedezimal () const { return static_cast<double>(minuten) / 60.0 + stunden; }
der cast ist hier nicht nötig, weil 60.0 sowieso schon ein double ist.
Th schrieb:
const Zeit& Zeit::operator =(const Zeit &zeit) { setze_zeit(zeit.stunde, zeit.minute); return *this; // das geänderte Objekt wieder als (konstante) Referenz zurückgeben // (Dereferenzierung, weil this ein Zeiger ist) }
hat es einen bestimmten grund, warum du eine konstante referenz zurückgibst?
-
Ja, um zu verhindern, daß z.B. jemand "(a=b).setze_zeit(0, 0)" schreibt (oder noch grausameren Code)!
Auch wenn meistens eine nicht-konstante Referenz zurückgegeben wird, habe ich es für meine eigenen Klassen so entschieden.
Der Rückgabetyp bei Operatoren ist ja nicht eindeutig definiert (manche geben auch einfach nichts zurück (void)).Daran braucht sich aber 'fraggelfragger' nicht zu halten...
-
es sah auch sehr gewollt aus, wollte nur sichergehen. widespread ist es ja nicht gerade.
-
Th schrieb:
Ja, um zu verhindern, daß z.B. jemand "(a=b).setze_zeit(0, 0)" schreibt (oder noch grausameren Code)!
Natürlich ist es unmöglich, absichtlich schlecht geschriebenen Code zu verhindern, und diese Art von Code kommt sicherlich nicht versehentlich (nur in solchen Fällen kommt ein Schutz in Frage) zustande. Zudem ist das jedenfalls in meinen Augen relativ harmloser Code, es ist ziemlich klar, was dieser bewirken würde. In diesem Fall habe ich immer das Gefühl, dass hier aus einer Mücke ein Elefant gemacht wird, ohne die Nachteile zu berücksichtigen.
Nicht zuletzt sollte nicht vergessen werden, dass so eine Klasse - Überraschung! - nicht kompatibel mit Standardcontainern ist.