class
-
hallo, danke für eure Antworte.
So ich glaube es gibt einen Missverständniss was das hier betrifft:
vorname [30] = '0';
das hat der professor so verlangt (denke ich zumindest). so hier ist die aufgabe damit keine missverständnise mehr vorkommen
**Daten:
· Das Programm soll die Daten von max. 16 Teilnehmern verwalten.
· Pro Teilnehmer werden Nachname, Vorname und Matrikelnummer verwaltet.
Ausgabe:
· Das Programm soll eine Teilnehmerliste ausgeben, in Form einer Tabelle wie folgt:
· Es soll die Spalten „Name“, „Vorname“ und „Matrikelnummer“ geben.
· Zunächst muss eine passende Überschrift ausgegeben werden.
· Dann folgen so viele Zeilen, wie es Teilnehmer gibt, für die Daten eingegeben
wurden.
Definieren Sie eine Klasse „Tellnehmer“ mit den Datenelementen
· 30 Zeichen Vorname,
· 30 Zeichen Nachname und
· einer Integer Matrikelnummer.
Programmieren Sie Konstruktoren für diese Klasse:
· Einen Standard-Konstruktor, der den Vornamen mit dem Nullstring initialisiert und
den Nachnamen den String “-“, sowie die Matrikelnummer auf 0 setzt.
· Einen zweiten Konstruktor mit 3 Parametern; zwei Parameter sind Strings für
Nachnamen und Vornamen, der dritte eine Integer für die Matrikelnummer.
· Evtl. können Sie beide Konstruktoren durch die Verwendung von Vorgabewerten
zu einem Konstruktor zusammenfassen.
Erstellen Sie eine Methode „print()“ für diese Klasse , die eine Zeile der Tabelle
schreibt, wenn es sich nicht um ein „leeres“ Objekt im Array handelt (Nachname “-“).
Verwenden Sie für die Ausgabe der Daten den stream „cout“. Alternativ können Sie
auch die aus C bekannte Funktion printf() verwenden.**
Was char vorname[30] und char nachname[30] betrifft, ich glaube mann muss definieren wie groß der String ist oder irre ich mich?
eine kleine Frage hätte ich noch, warum muss ich einen Zeiger benutzen?
-
krümelkacker schrieb:
Die Formulierung deines Lehrers "restlichen 12 Objekte wird der Standardkonstruktor befüllen" ist etwas ungünstig, da ints und char-Arrays und damit auch Aggregate, die nur aus ints und char-Arrays bestehen, keine "Standardkonstruktoren" haben, die das machen würden, was Dein Lehrer erwartet. Hier, bei dieser Initialisierungssyntax, wird eine sogenannte "zero initialization" für all die restlichen Elemente durchgeführt.
Ich korrigiere: Es handelt sich um eine "Default-Initialisierung" der restlichen Elemente (was aber im Fall von
intundcharauf eine "zero initialization" hinaus läuft). Das gilt auch für POD-Aggregate, die keine vom Compiler implizit erzeugten Konstruktoren haben.Zitat aus dem C++ Standard, §8.5.1/7:
If there are fewer initializers in the list than there are members in the aggregate, then each member not explicitly initialized shall be default-initialized.
wobei default-initialized so definiert wird, §8.5/5:
To default-initialize an object of type T means:
- if T is a non-POD class type (clause 9), the default constructor for T is called (and the initialization is ill-formed if T has no accessible default constructor);
- if T is an array type, each element is default-initialized;
- otherwise, the object is zero initialized;zero-initialization steht gleich darüber erklärt. Ich spare mir das zitieren aber. Es ist wahrscheinlich sowieso Overkill. Aber es macht zumindest deutlich, dass es relativ viele Regeln gibt, die man nur durch Rumprobieren schlecht erraten kann.
Bei der Gelegenheit verweise ich auch noch auf camper's Post "Kleine Taxonomie für Typen".
-
pava schrieb:
So ich glaube es gibt einen Missverständniss was das hier betrifft:
vorname [30] = '0';
das hat der professor so verlangt (denke ich zumindest).Bestimmt nicht.
pava schrieb:
so hier ist die aufgabe damit keine missverständnise mehr vorkommen

[...]Ich sehe da keine Bemerkung zur Art der Initialisierung. Aber nachdem, was er verlangt, kann die Klasse Teilnehmer kein Aggregat-Typ mehr sein. Ein Array davon müsste sich aber immernoch ähnlich initialisieren lassen:
int main() { Teilnehmer liste[16] = { Teilnemher("Hinz", "Kunz", 1234), Teilnemher("Dings", "Bums", 4321) }; }pava schrieb:
Was char vorname[30] und char nachname[30] betrifft, ich glaube mann muss definieren wie groß der String ist oder irre ich mich?
Ja, is ja auch richtig. Aber das [30] gehört nicht zum Namen des Arrays dazu. Ich weiß nicht, warum Du glaubst, dass das [30] überall sonst noch dazugeschrieben werden muss.
pava schrieb:
eine kleine Frage hätte ich noch, warum muss ich einen Zeiger benutzen?
Wenn Du einen Konstruktor schreiben willst, der Deine Arrays befüllt, müsstest Du dich mit Funktionen wie sie im Header <cstring> zu finden sind, rumärgern. Diese Funktionen arbeiten mit Zeigern. Das sind Funktionen, die zB die Länge von C-Strings berechnen (Nullterminierung suchen), einen C-String kopieren, etc etc etc. Alles Käse eigentlich, wenn Du nicht std::string benutzen darfst. Käse, weil es damit relativ einfach wird, sich in den Fuß zu schießen.
Ich rate Dir, das, was der Prof erzählt, kritisch zu betrachten und in dem einen oder anderen guten Lehrbuch nachzuschlagen. Es mag nur sein didaktischer Plan sein, dass die Studenten sich mit C-Strings rumärgern sollen, bevor sie std::string kennenlernen und dann die Vorzüge richtig zu schätzen wissen. Es kann aber auch sein, dass der Prof von C++ nicht ganz so viel Ahnung hat, und Euch in Wirklichkeit "C mit Klassen" beibringt, ohne zu erwähnen, dass man sich mit Klassen (und eigenen Kopierkonstruktoren, Destruktoren, Zuweisungsoperatoren, überladenen Operatoren) ganz nette und leicht benutzbare eigene Typen bauen kann (wie zB std::string), auf die man aufbauen kann. Das Stichwort hier ist Abstraktion und Kapselung. Sorry, ich habe keine Lust, mir jedes Mal Gedanken zu machen, ob mein char-Array auch groß genug ist, und wie ich am besten Zeichenketten ohne Pufferüberläufe kopiere. Der eingefleischte C-Programmierer mag das anders sehen, doch auch in Projekten von C++-Hassern findet man Abstraktionsansätze für Zeichenketten, die auf so etwas ähnliches wie std::strig hinauslaufen -- nur dass man immer noch recht viel bei dem aufpassen muss, was man da tut; denn es gibt ja keine Kopierkonstruktoren, Destruktoren und überladene Zuweisungsoperatoren in C.
-
vielen dank an alle die mir geholfen haben
, ich bin jetzt dank eure hilfe einbischen schlauer geworden, und weiss teilweise was für Fehler ich gemacht habe. Den Rest muss ich wie ihr das gesagt habt in meinem Buch noch lesen. Ich habe das Buch go to c++. ist das Buch ok? ich finde manchmal könnten ein paar mehr Beispiele nichts schaden.
ach ja noch etwas, wäre es denn richtig so ?char vorname [0] = '0';
-
pava schrieb:
vielen dank an alle die mir geholfen haben
, ich bin jetzt dank eure hilfe einbischen schlauer geworden, und weiss teilweise was für Fehler ich gemacht habe. Den Rest muss ich wie ihr das gesagt habt in meinem Buch noch lesen. Ich habe das Buch go to c++. ist das Buch ok? ich finde manchmal könnten ein paar mehr Beispiele nichts schaden.
ach ja noch etwas, wäre es denn richtig so ?char vorname [0] = '0';Wenn du aus dem String einen Leerstring machen willst, muss es so aussehen:
char vorname [0] = 0;Das Stringende wird von einer binären Null signalisiert, nicht von dem Zeichen '0' (dann dürfte in deinen Strings ja nie '0' vorkommen, was dich leicht einschränken würde
).
-
pava schrieb:
Den Rest muss ich wie ihr das gesagt habt in meinem Buch noch lesen. Ich habe das Buch go to c++. ist das Buch ok?
Das kenne ich nicht. Es klingt vom Titel her aber nicht so vielversprechend.
pava schrieb:
ich finde manchmal könnten ein paar mehr Beispiele nichts schaden.
ach ja noch etwas, wäre es denn richtig so ?char vorname [0] = '0';Nein. Das sollte gar nicht kompilieren; denn Du definierst hier ein Array mit 0 Elementen. Und mit "definieren" meinte ich das, was vor dem Gleich steht. Das ab dem Gleich ist die Initialisierung, die auch noch falsch gewesen wäre.
Beispiel, welches Du sehen willst, aber wegen dem char-Array eigentlich etwas frickelig ist:
#include <iostream> #include <cstring> const int name_feld_laenge = 30; class person { char name_[name_feld_laenge]; public: person() { name_[0] = '\0'; } explicit person(const char* zeiger); const char* name() const { return &name_[0]; } }; person::person(const char* zeiger) { std::strncpy(&name_[0],zeiger,name_feld_laenge); // strncpy garantiert aber keine Nullterminierung im Ziel // Wir müssen daher Hand anlegen: name_[name_feld_laenge-1] = '\0'; } int main() { person liste[3] = { person("Heinz ist nett und dieser String ist zu lang"), person("Uwe") }; std::cout << liste[0].name() << '\n'; std::cout << liste[1].name() << '\n'; }wobei es dies hier eigentlich auch getan hätte:
#include <iostream> #include <string> struct person { std::string name; }; int main() { person liste[3] = { {"Heinz ist nett und dieser String ist nicht zu lang"}, {"Uwe"} }; std::cout << liste[0].name << '\n'; std::cout << liste[1].name << '\n'; }Nur das will Dein Prof nicht sehen, weil er entweder denkt, es sei besser C vor C++ zu lernen oder weil er nicht weiß, wie "schönes" C++ aussehen kann.
Die Sachen aus der Standardbibliothek (std::string, std::strncpy, etc) kann man zB hier nachgucken.
-
so dank eure hilfe habe ich mein code jetzt einbischen verbessert, ich konnte leider nicht alles umsetzen bzw ändern was ihr mir empfohlen habt zb mit [30] muss weg usw.. weil dann bekam ich fehlermeldungen.
so kann man das Programm fehlerfrei kompilieren, aber ich habe ein Problem mit der Ausgabe.
PS: Schauen Sie die main funktion bitte an da habe ich das problem.#include <iostream> #include <cstring> using namespace std; class teilnehmer { private : char vorname [30] ; char nachname [30]; int matrikelnummer; public: teilnehmer (); teilnehmer (char v[30], int m, char n[30]); void print (); }; teilnehmer :: teilnehmer () { vorname [0] = 0; nachname [0] = '-'; int matrikelnummer = 0; } teilnehmer :: teilnehmer(char v [30], int m, char n[30]) { vorname [30] = v [30]; matrikelnummer = m; nachname [30] = n [30]; } void teilnehmer :: print () { if (nachname [0] != '-') { cout << "Der Nachname ist : " << nachname << endl; } } int main () { teilnehmer tabelle[16] = { teilnehmer ("Kevin", 123456, "Mueller"), teilnehmer ("Franz", 112233, "Schuhmacher"), teilnehmer ("Lisa", 102356 , "Fritz"), teilnehmer ("Manfred", 258963, "Schmitt"), }; int i; for (i=0 ; i<16 ; i++) { /*das Programm kann man Fehlerfrei kompilieren wenn man die cout hier unten nicht benutz, aber ich brauche die ausgabe, kann mir jemand bitte zeigen wie die ausgabe richtig wäre?*/ cout << tabelle [i].vorname << endl; cout << tabelle[i].matrikelnummer << endl; } return 0; }
-
Du kannst nicht einfach auf die privaten Attribute einer Klasse zugreifen. Private ist ja gerade genau dafür da! Du musst irgendeine Schnittstelle im public-Bereich deiner Teilnehmerklasse definieren über die du die gewünschten Ausgaben machen kannst. Die übliche Vorgehensweise wäre die Überladung des Operators<<. Das ist aber nicht unbedingt etwas für deinen Kenntnisstand. Die billige Alternative wäre so etwas wie deine print-Funktion, aber stattdessen mit den von dir gewünschten Ausgaben. Oder noch billiger so etwas wie get_matrikelnummer(), dass dann einfach die Matrikelnummer zurückgibt.
-
Da sind noch immer viele Macken drin, die ich beim ersten Mal schon kritisiert habe. Du solltest das, was gesagt wurde, ernst nehmen.
pava schrieb:
teilnehmer (char v[30], int m, char n[30]);müsste tatsächlich heißen:
teilnehmer (const char v[30], int m, const char n[30]);wobei die 30 eigentlich überflüssig ist. Man könnte auch const char[] dafür schreiben -- kommt auf dasselbe raus. v und n sind nuneinmal Zeiger hier und keine Arrays -- wegen der angesprochenen Typtransformation.
pava schrieb:
void print ();Hier fehlt ein const am Ende. Sollte so aussehen:
void print () const;(Die Funktion print muss/will den Zustand des Objekts nicht ändern.)
pava schrieb:
teilnehmer :: teilnehmer(char v [30], int m, char n[30]) { vorname [30] = v [30]; matrikelnummer = m; nachname [30] = n [30]; }Man hat Dir schon erklärt, dass das hier sinnfrei ist, was Du machst. Ich habe Dir sogar schon gezeigt, wie man die C-Strings hier richtig kopieren würde. Das [30] hier ist immer noch Nonsense. Klar, es lässt Dich Dein Programm kompilieren, aber es ergibt keinen Sinn. Es macht nicht das, was Du willst. Du willst eine Kette von Zeichen kopieren, maximal 30 (einschließlich Nullterminierung). Was Du machst, ist das 31. Zeichen kopieren, welches im Falle von vorname und nachname nicht existiert, weil Du ja nur 30 Zeichen hast und welches im Falle von v und n auch nicht existieren muss. Du popelst also in einem Speicher rum, der Dir nicht gehört und von dem Du nicht weißt, dass es ihn überhaupt gibt. --> undefiniertes Verhalten
pava schrieb:
void teilnehmer :: print ()hier kommt auch noch ein const an's Ende.
pava schrieb:
for (i=0 ; i<16 ; i++) { /* das Programm kann man Fehlerfrei kompilieren wenn man die cout hier unten nicht benutz, aber ich brauche die ausgabe, kann mir jemand bitte zeigen wie die ausgabe richtig wäre? */ cout << tabelle .vorname << endl; cout << tabelle[i].matrikelnummer << endl; }Dass man es fehlerfrei kompilieren kann, heißt nicht, dass der Rest in Ordnung ist. Natürlich kannst Du auf [i]private* Elemente nicht ohne weiteres zugreifen. Das ist ja der Witz von private. Wozu hast Du die print-Funktion? Außerdem solltest Du den Konstanten einen Namen geben, so dass Du sie ändern kannst, indem Du Dein Programm nur an einer Stelle ändern musst.
const int max_teiln = 16; // <-- eine Stelle. Diese 16 taucht sonst // nirgens mehr auf, nur der Name max_teiln teilnehmer tabelle[max_teiln] = { u.s.w. }; for (int i=0; i<max_teiln; ++i) { tabelle[i].print(); }
-
hallo, danke nochmal für alle die mir geantwortet haben.
@ Krümelkacker:
sorry ich wollte nicht das es so rüber kommt. Natürlich habe ich eure Ratschläge ernst genommen, aber ich habe mich halt gefreut als ich das programm Fehlerfrei kompilierte, aber jetzt weiss ich dass das nicht viel heisst.der code musste also so aussehen, wenn ich dich dieses mal richtig verstanden habe:
teilnehmer :: teilnehmer(const char v [], int m, const char n[]) { vorname [0] = v [0] ; matrikelnummer = m; nachname [0] = n [0] ;somit greife ich jetzt auf das erste Element zu. richtig?
Gruß pava.
-
pava schrieb:
teilnehmer :: teilnehmer(const char v [], int m, const char n[]) { vorname [0] = v [0] ; matrikelnummer = m; nachname [0] = n [0] ;somit greife ich jetzt auf das erste Element zu. richtig?
Genau. Und dahinter steht immer noch Müll drinnen...
Ein Array besteht nämlich meistens aus mehr als nur einem Element und du willst doch sicherlich alle Elemente kopieren. Und auch dazu hat dir krümelkacker schon die Lösung präsentiert: std::strncpy.
-
hallo,
nach kurzer Besprechung mit dem Professor ist es endlich soweit, ich habe es geschafft, und mein Programm sieht jetzt so aus :(Endphase)
#include <iostream> #include <string> using namespace std; class teilnehmer { private : string vorname ; string nachname ; int matrikelnummer; public: teilnehmer (); teilnehmer (string v, int m, string n); void print (); }; teilnehmer :: teilnehmer () { vorname = ""; nachname = "-"; matrikelnummer = 0; } teilnehmer :: teilnehmer(string v, int m, string n) { vorname = v ; matrikelnummer = m; nachname = n ; } void teilnehmer :: print () { if (nachname != "-") { cout << "Der Vorname : " << vorname << " und die Matrikelnummer ist : "<< matrikelnummer << endl; cout << "Der Nachname ist : " << nachname <<endl; } } int main () { teilnehmer tabelle[16] = { teilnehmer ("Kevin", 123456, "Mueller"), teilnehmer ("Franz", 112233, "Schuhmacher"), teilnehmer ("Lisa", 102356 , "Fritz"), teilnehmer ("Manfred", 258963, "Schmitt"), }; int i; for (i=0 ; i<16 ; i++) { tabelle[i].print(); }; return 0; }so ich glaube jetzt gibts nichts mehr zu meckern oder? ausser bei
const int max_teilnehmer = 16;danke schön nochmal und bis zum nächsten Programm.
MfG Pava
-
Da gibts noch zwei Sachen, die mir gerade so aufgefallen sind:
- Formatierung - Formatier deinen Code anständig! Das ist schreklick zu lesen!
- Nutze Initialisierungslisten
-
drakon schrieb:
Da gibts noch zwei Sachen, die mir gerade so aufgefallen sind:
- Formatierung - Formatier deinen Code anständig! Das ist schreklick zu lesen!
- Nutze Initialisierungslisten
Sry ich bin Anfänger, wie meinst du das mit der Formatierung?
-
An gewissen Stellen ist deine Einrückung ziemlich unübersichtlich.
Wenn ein neuer Block mit { beginnt, rückst du eine Ebene mehr ein, bei } eine weniger. Dadurch sieht der Code schon viel lesbarer aus.
-
pava schrieb:
Sry ich bin Anfänger, wie meinst du das mit der Formatierung?
Einrückung, diese auch konsistent durchziehen.
Die ";" ebenso konsistent setzen.
Keine unnötigen Leerzeilen und Leerzeichen.
USW.
-