Herzlich Willkommen, lieber Gast!
  Sie befinden sich hier:

  Forum » C / C++ (ANSI-Standard) » *hilfe* - Arbeit in C++ aber keine Ahnung

Forum | Hilfe | Team | Links | Impressum | > Suche < | Mitglieder | Registrieren | Einloggen
  Quicklinks: MSDN-Online || STL || clib Reference Grundlagen || Literatur || E-Books || Zubehör || > F.A.Q. < || Downloads   

Autor Thread - Seiten: [ 1 ] > 2 < [ 3 ]
010
14.03.2006, 17:09 Uhr
Hans
Library Walker
(Operator)



Zitat von Spacelord:
@Hans:
Mal ehrlich,wenn den Schülern da wirklich so nen Code wie oben eingetrichtert wird,dann kannst du eigentlich nur nochmal bei null anfangen.


Zitat von Hans:

Dazu (also dem Code) kann ich jetzt nix sagen, werde es mir aber nachher mal näher ansehen, - mal sehen, wieviel hängen geblieben ist.

Hi,

hier mal die Ergebnisse meiner Untersuchungen dieses Programms:
Als erstes fällt auf, das der Verfasser anscheinend keine Ahnung hat, wie Kommentare aussehen müssen. Wenn man das so dem Compiler vorsetzt, dann erhält man über 20 Fehlermeldungen. Nachdem der Kommentar als solcher kenntlich gemacht wurde, reduzieren sich die Fehler auf 4, dafür hagelt es aber jede Menge Warnungen.
Dann fällt bei den #include-Direktiven auf, das C und C++ munter gemixt wurden. Wie in diesem Forum schon häufiger zu lesen war, sollte man das nicht tun, weil es zu Problemen führen kann. Das scheint mir hier auch der Fall zu sein, wenn der Compiler folgendes moniert:

Zitat von Borland C++ 5.5.1 for Win32:
Error E2285 Schulproggy.cpp 291: Could not find a match for 'strcpy(string,string)' in function Konto::init(string,string,int,float,float,float,float)

Ach ja,
C++:
#include <string.h>
steht zweimal da; wozu soll das denn gut sein?

Als nächstes ist da das
C++:
typedef char string[30];

das Spacelord ja schon angesprochen hat. Oben zitierte Fehlermeldung erhalte ich, wenn ich dieses typedef auskommentiere. Wenn ich es drin lasse, krieg ich diese Fehlermeldung:

Zitat von borland C++ Compiler:
Error E2015 Schulproggy.cpp 20: Ambiguity between 'string' and 'std::string'

Da kommen sich also die C-Funktionen aus string.h und die C++ - Äquivalente aus std::string in die Quere... Schön. - ähh Sch****e!

Bei der Deklaration der Klasse fällt mir auf, das der Destruktor fehlt. Okay, da gibt es einen Standard-destruktor, also lassen wir das erst mal. Obwohl es wahrscheinlich kein guter Stil ist.
Aber dann: Der Konstruktor mit den vielen Parametern, und zwei Zeilen tiefer eine Funktion init(...) mit genau den selben Parametern. Vergleicht man die Definitionen der beiden, stellt man fest, das beides der Selbe Code ist. Anscheinend hat da jemand den Sinn von Konstruktoren nicht verstanden. - Oder das ist ein bewusst eingebauter Fehler, den die Lernenden finden sollen...

Etwas eigenartig finde ich auch die Funktion suchen(), die keine Parameter hat. Normalerweise sollte man einer solchen Funktion doch mitteilen, was man sucht, oder nicht?! - Könnte natürlich auch sein, dass das nur ein (umständlicher?) Weg ist, um an die als private deklarierte Kontonummer zu kommen. Aber dann ist der Funktionsname eher verwirrend, zumal in der Definition auch nur return kontonummer; steht.

Kommen wir zur main()-Funktion. Der Initialisierungsteil bereitet mir irgendwie Kopfschmerzen. Da wird doch tatsächlich diese doofe init-Funktion benutzt, um die einzelnen Instanzen der Klasse zu initialisieren. - Ich dachte, dafür sind Konstruktoren da!?
Was ich von dieser Konstruktion
C++:
Konto *Kunde = new Konto[anzahl_kunden];

halten soll, weis ich nicht so recht. Aber wenn ich es zusammen mit der nachfolgenden initialisierung betrachtet, scheint mir da irgendwas grundsätzlich dran falsch zu sein. Und falls es doch richtig sein sollte, so gibt es da doch bestimmt auch bessere Lösungen.

Als nächstes: Was soll diese Sprungmarke Menue: vor der while-schleife? - Anscheinend sollte das ein Kommentar sein...
Danach die Auswahl, wobei ich mich frage, warum die Variable auswahl global definiert ist, obwohl sie nur in main benötigt wird. Dann ist ihr Wert beim Programmstart unbestimmt, sie wird aber bereits in der Abbruchbedingung der Schleife verwendet. Das kann doch nicht gut gehen! => Logischer Fehler.
Was soll das getch() jedesmal am Ende eines case-Blocks? - Das Konsolenfenster offen halten?

Weiter fällt mit die Funktion Konto::ausgabe() auf, in der printf benutzt wird. Aber formatierte Ausgaben kann man doch auch mit cout bewerkstelligen. Ich weis zwar (noch) nicht genau, wie, aber ich hab hier im Forum schon öfter gesehen, das es geht. - Hat AFAIK was mit ostream zu tun, aber wie gesagt, da kenn ich mich nicht aus.

Zusammenfassend würde ich sagen, das dieses Programm eine Katastrophe ist, weil es viel zu viele Fehler enthält. Selbst für eine Klausuraufgabe, wo man die Fehler alle finden und beheben soll, ist es meiner Ansicht nach zu lang. Also im Grunde gehört es wirklich eher in den Müll, als in eine Lehrveranstaltung.

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
011
14.03.2006, 22:45 Uhr
Karldin Shinowa
Professional Noob



aber gute Analyse

kleine Frage noch wieso soll man immer Konstruktor und Destruktor definieren wenn man keinen braucht???
mfg Karldin
--
Ich will die Welt verbessern, doch Gott gibt mir nicht den Code.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
012
14.03.2006, 22:49 Uhr
FloSoft
Medialer Over-Flow
(Administrator)



Zitat von Karldin Shinowa:

kleine Frage noch wieso soll man immer Konstruktor und Destruktor definieren wenn man keinen braucht???

muss man nicht, schaut nur besser aus
--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
013
14.03.2006, 23:53 Uhr
Hans
Library Walker
(Operator)



Zitat von Karldin Shinowa:
kleine Frage noch wieso soll man immer Konstruktor und Destruktor definieren wenn man keinen braucht???
mfg Karldin

Kannst Du mir mal erklären, warum man da keine braucht?

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
014
15.03.2006, 00:29 Uhr
ref




Zitat von Verfasser:

kleine Frage noch wieso soll man immer Konstruktor und Destruktor definieren wenn man keinen braucht???



Wenn man überhaupt keine Konstruktoren deklariert, erzeugt der Compiler automatisch einen Standardkonstruktor (der keine parameter übernimmt).
--
Man kann ein Problem nicht mit der gleichen Denkweise lösen, mit der es erschaffen wurde. (Albert Einstein)
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
015
15.03.2006, 06:57 Uhr
(un)wissender
Niveauwart


Ach ja,

C++:
Konto *Kunde = new Konto[anzahl_kunden];


Das ist schon in Ordnung. Normale Arraydeklaration/Definition.
--
Wer früher stirbt ist länger tot.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
016
15.03.2006, 09:13 Uhr
ao

(Operator)


Hallo Hans, hier ist mal mein Senf dazu.

Zitat von Hans:
Wenn man das so dem Compiler vorsetzt, dann erhält man über 20 Fehlermeldungen.

Bei mir (VC 6) läuft der Code ohne Fehler durch. Die Warnungen (die nur auf höchstem Warninglevel erscheinen) betreffen Umwandlungen von double nach float und von int nach float, das unreferenzierte Label und die unreferenzierte Variable "versuche", unschön, aber in diesem Zusammenhang eher harmlos.

Du solltest vielleicht nicht gerade Borland 5.5 als Referenz für einen standard-konformen Compiler nehmen, dafür ist der nämlich etwas zu alt.

Zitat:
Dann fällt bei den #include-Direktiven auf, das C und C++ munter gemixt wurden.

Das stimmt, sowas sollte man nicht machen. Man sollte sich für *eine* Lib entscheiden, Standard-C oder Standard-C++, und dabei bleiben. Zumal tatsächlich printf und cout nebeneinander benutzt werden, und das ist dem Autor dick anzukreiden.

Zitat:
Ach ja,
C++:
#include <string.h>
steht zweimal da; wozu soll das denn gut sein?

Eine Nachlässigkeit, die aber nicht schadet, weil string.h normalerweise einen Include-Guard hat.

Zitat:

Zitat von borland C++ Compiler:
Error E2015 Schulproggy.cpp 20: Ambiguity between 'string' and 'std::string'

Da kommen sich also die C-Funktionen aus string.h und die C++ - Äquivalente aus std::string in die Quere... Schön. - ähh Sch****e!

Siehe oben. Deine nicht ganz top-aktuelle C++-Lib hat string noch nicht im Namespace std, oder sie bringt überflüssigerweise ihr eigenes "using namespace std;" mit; würde sie das richtig machen, gäbs hier keinen Fehler.

Zitat:
Bei der Deklaration der Klasse fällt mir auf, das der Destruktor fehlt. Okay, da gibt es einen Standard-destruktor, ...

... mit dem man eigentlich zurechtkommt, weil die Klasse nichts hat, was besonders zu zerlegen ist.

Zitat:
Aber dann: Der Konstruktor mit den vielen Parametern, und zwei Zeilen tiefer eine Funktion init(...) mit genau den selben Parametern. Vergleicht man die Definitionen der beiden, stellt man fest, das beides der Selbe Code ist. Anscheinend hat da jemand den Sinn von Konstruktoren nicht verstanden.

Vordergründig ergibt das schon Sinn. Ein Konto-Objekt kann entweder mit Parametern konstruiert werden oder default-konstruiert und dann mit Parametern initialisiert werden. Der zweite Weg wird gebraucht, wenn man ein Array von Konto-Objekten anlegt, so wie es weiter unten mit new Konto [anzahl_kunden] gemacht wird. C++ erlaubt nämlich hier nur die Verwendung des Default-Konstruktors. Daher könnte der "naive" C-Programmierer denken, dass er hier tatsächlich beides braucht.
Doof ist allerdings, dass der Initialisierungs-Code kopiert wurde und jetzt an zwei Stellen gepflegt werden muss (Konstruktor und Init-Funktion), sowas geht in der Regel nicht lange gut. Besser wäre, im Konstruktor Init aufzurufen.
Richtiges C++ wäre, die Konten nicht in einem C-Style-Array zu verwalten, sondern in einem STL-Container, z.B. std::vector<Konto> oder std::list<Konto>. Dann könnte man nämlich parameter-konstruierte Konto-Objekte in den Container stecken, der dynamisch wachsen würde, und bräuchte die Init-Geschichte gar nicht.

Zitat:
Etwas eigenartig finde ich auch die Funktion suchen(), die keine Parameter hat.

Die sollte allerdings besser "get_kontonummer ()" oder so heißen.

Zitat:
Kommen wir zur main()-Funktion ... Da wird doch tatsächlich diese doofe init-Funktion benutzt ... gibt es da doch bestimmt auch bessere Lösungen.

Jawoll, siehe oben.

Zitat:
Als nächstes: Was soll diese Sprungmarke Menue: vor der while-schleife? -

Altlast aus früheren Jahrhunderten. Wird nirgendwo mehr verwendet und trägt nur zur Verwirrung bei. Sollte gelöscht werden.

Zitat:
Danach die Auswahl, wobei ich mich frage, warum die Variable auswahl global definiert ist, obwohl sie nur in main benötigt wird. Dann ist ihr Wert beim Programmstart unbestimmt, sie wird aber bereits in der Abbruchbedingung der Schleife verwendet. Das kann doch nicht gut gehen! => Logischer Fehler.

NACK. Globale Variablen werden mit 0 initialisiert, kein Fehler. Aber es stimmt, die Variable könnte genausogut lokal sein, bräuchte dann aber eine Initialisierung.

Zitat:
Was soll das getch() jedesmal am Ende eines case-Blocks?

Das Programm anhalten, damit der Benutzer die letzte Ausgabe sehen kann. Wenns schee macht ...

Zitat:
Weiter fällt mit die Funktion Konto::ausgabe() auf, in der printf benutzt wird. Aber formatierte Ausgaben kann man doch auch mit cout bewerkstelligen. Ich weis zwar (noch) nicht genau, wie ...

Der Autor offenbar auch nicht. Aber es stimmt, man sollte entweder printf oder cout nehmen, aber nicht beides. Die Mischung kann - muss aber nicht - zu lustigem Durcheinander auf dem Bildschirm führen.

Zitat:
Zusammenfassend würde ich sagen, das dieses Programm eine Katastrophe ist, weil es viel zu viele Fehler enthält ...

Zu den gröbsten Fehlern gehört IMHO der selbstgebastelte Typ string, der ohne jedes Range-Checking blind verwendet wird. Namen über 30 Zeichen sind zwar in unseren Breiten selten, aber wenn beim ersten pakistanischen Kunden, der ein Konto eröffnen will, gleich die EDV abstürzt, ist das nicht so witzig.

Dazu kommt dieses C-C++-Mischmasch (Datenhaltung im C-Style-Array, wo ein STL-Container viel passender wäre), das einem viele nützliche Hilfen verbaut, z.B. Suchen auf dem Container, und einen zwingt, den ganzen Mist selber zu machen.

Und dann sind da noch etliche Nachlässigkeiten, die zwar nicht gleich zu Fehlern führen, aber den Code missverständlich und unsauber machen.

Wirklich kein Vorführstück.

ao

Dieser Post wurde am 15.03.2006 um 09:17 Uhr von ao editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
017
15.03.2006, 09:14 Uhr
FloSoft
Medialer Over-Flow
(Administrator)



Zitat von ref:

Zitat:

kleine Frage noch wieso soll man immer Konstruktor und Destruktor definieren wenn man keinen braucht???



Wenn man überhaupt keine Konstruktoren deklariert, erzeugt der Compiler automatisch einen Standardkonstruktor (der keine parameter übernimmt).


und destruktor natürlich auch


C++:
class Foo
{
public:
  int bar;
};



ist völlig korrekt, der compiler fügt automatisch Foo() und ~Foo() hinzu.
--
class God : public ChuckNorris { };
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
018
15.03.2006, 09:43 Uhr
ao

(Operator)



Zitat von ao:
Wirklich kein Vorführstück.


Noch was hinterher.

Wenn das ein Lehrbeispiel für irgendwas sein soll, dann nur dafür, dass man bestehende C-Programme nicht mal eben schnell nach C++ überträgt, sondern besser von Grund auf neu schreibt. Auch wenn es kompiliert und läuft, es ist in der Regel kein schöner Code, und es kann viele Dinge, die es in C++ geschenkt gibt, nicht nutzen.

Solche Dinge entstehen fast automatisch, wenn der Programmierer, der das macht, C deutlich besser kann als C++.

"C++ ist doch nur ein besseres C, was gibts da groß zu lernen?" - Weit gefehlt, C++ kann viel mehr und macht vor allem viele Dinge grundlegend anders, aber das muss man wissen! Die .c-Files nach .cpp umbenennen, malloc durch new ersetzen und mit ein paar expliziten Casts die ärgsten Compilerfehler beheben - das ist es nicht.

ao
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
019
15.03.2006, 12:28 Uhr
Hans
Library Walker
(Operator)


@ao: Danke für die Erläuterungen. Jetzt weis ich wenigstens, wo ich in Zukunft was zu tun haben werde, wenn ich mal wieder mit C++ anfange.
Jetzt würde mich noch interessieren, was Spacelord und/oder Virtual oder auch beefy dazu meinen.
Was meinen Compiler angeht: ich weis das der alt und nicht mehr ganz Standardkonform ist. Hab aber derzeit keinen anderen. D.h. hab hier zwar noch eine CD mit Watcom C++ 1.2 drauf, aber der ist ja auch nicht mehr besonders aktuell...

Hans
--
Man muss nicht alles wissen, aber man sollte wissen, wo es steht. Zum Beispiel hier: Nachdenkseiten oder Infoportal Globalisierung.

Dieser Post wurde am 15.03.2006 um 12:31 Uhr von Hans editiert.
 
Profil || Private Message || Suche Download || Zitatantwort || Editieren || Löschen || IP
Seiten: [ 1 ] > 2 < [ 3 ]     [ C / C++ (ANSI-Standard) ]  


ThWBoard 2.73 FloSoft-Edition
© by Paul Baecher & Felix Gonschorek (www.thwboard.de)

Anpassungen des Forums
© by Flo-Soft (www.flo-soft.de)

Sie sind Besucher: