Von "C++ von A bis z" zu "C++ Primer"
-
Hallo Forengemeinde,
ich hab hier schon des öfteren gelesen, dass das Buch "C++ von A bis Z" zum lernen nicht gut geeignet ist. Ich oute mich jetzt hier einmal, dass ich C++ hauptsächlich mit diesem Buch gelernt habe. Um jetzt verschieden Themen nachzuarbeiten, die von J. Wolf vielleicht nicht ganz richtig oder was auch immer beschrieben wurden, möchte ich nun mein Wissen mit dem Primer erweitern. Da ich mir das Buch aus der Uni Bibliothek ausgeliehen hab, ist meine Zeit nur begrenzt und kann mir das Buch daher nicht vollständig aneignen.Daher wollte ich von euch wissen, welche Kapitel in diesem Buch ihr mir raten würdet zu lesen.
-
Alle.
-
Kannst du dir selbst denken (oder nicht? wenn nicht, dann schlecht):
- STL- OOP- C++ - Standard-Bibliothekach, lies einfach das ganze buch :p Kapitel:
8,9,10,12,(14),16Wenn du eben schon Ahnung von c++ hast.Am besten aber alles nacheinander, es macht ja keinen Sinn sachen zu lernen, die auf unbekanntem Basieren ;)Wieviel kannste 'n so?Alles
-
Alle.
-
SeppJ schrieb:
Alle.
+1
-
Vielleicht noch eine Begründung hinterher: Dir mag ja so scheinen, als würden dir nur bestimmte Bereiche fehlen (also als ob Hackers Antwort richtig wäre), aber Herr Wolf hat auch einen schrecklichen Stil, den du dir besser wieder abgewöhnen solltest. Weiterhin erzählt er nicht nur manche wichtige Sachen nicht, sondern erklärt auch viele einfache Sachen falsch oder ungenau. Im großen und ganzen solltest du möglichst alles verlernen, das du gelernt hast und das neue Buch gänzlich von vorne an durchlesen. Da du schon eine grundlegende Vorstellung von C++ hast, wird das auch sehr schnell gehen. Wenn du Beispielaufgaben in dem Buch löst, benutze nicht den Stil und die Mittel zu benutzen die du von JW kennst, sondern zwing dich dazu das so zu machen wie im Primer.
-
Ich würde es zwei Mal lesen. Einmal, um dir das J.W.-Halbwissen auszutreiben und einmal, um die Dinge richtig zu lernen
-
Ach, SeppJ, ich hab nur die Sachen aufgelistet, die IMHO am schlechtesten erklärt und dargestellt wurden
@seux: Wenn du nochmal konkreteres zu JW haben möchtest - es gibt mittlerweile viele Threads zu diesem 'Thema'. Wer sucht, der findet.
-
Von mir auch ein Nachschub: Es gibt die Sprache C++, die kannste jetzt. Und es gibt den Stil C++, den kannste nicht. Den braucht man aber auch ganz dringend. Die Sprache ist viel zu schwierig, unintuitiv und gefählich, um sie naiv zu benutzen.
Zum Beispiel, auch wenn Du in Sachen Vererbung alle Schlüsselwörter kennst, sogar Sonderfachwissen besitzt, wie daß pur virtuelle Destruktoren trotz Abstraktheit eine Implementierung brauchen, weil sie doch aufgerufen werden, so ist das nur die Sprache. Wenn Du nach Wolf dann Wurst von Supermarkt erben lassen wirst, wirst Du zwangsläufig auf die Schnauze fallen.
-
-
Nexus schrieb:
Ich würde es zwei Mal lesen. Einmal, um dir das J.W.-Halbwissen auszutreiben und einmal, um die Dinge richtig zu lernen
Ich denke, die Zeit wird noch besser genutzt, wenn er nach dem Primer noch Meyers Effektiv C++ Programmieren nachschiebt, statt den Primer zweimal zu lesen.
-
Okay, hätte jetzt nicht gedacht, dass das wirklich so extrem ist. Immerhin hab ich noch zwei andere Bücher über C++ und die Gefiehlen mir überhaupt nicht (eins von Markt und Technik, was ein totaler reinfall war, und noch ein anderes, was mir ebenfalls nicht gefiehl).
Immerhin programmier ich nun doch schon etwas länger und mir hat noch nie jemand gesagt, das ich nen schlechten Stil hätte (also weder mein Informatik Lehrer im Abitur noch jemand hier im Forum, immerhin müsste das doch auffallen.).
Ich bedanke mich schonmal für euren Rat, dann werde ich mich mal mit dem Primer beschäftigen...
-
seux schrieb:
gefiehl
Lass mich raten, wegen deiner Rechtschreibung hat dich auch noch keiner kritisiert, oder
*scnr*
-
seux schrieb:
Okay, hätte jetzt nicht gedacht, dass das wirklich so extrem ist. Immerhin hab ich noch zwei andere Bücher über C++ und die Gefiehlen mir überhaupt nicht (eins von Markt und Technik, was ein totaler reinfall war, und noch ein anderes, was mir ebenfalls nicht gefiehl).
Ui. J.W. und Markt und Technik - da haste gleich zweimal ziemlich tief ins Klo gegriffen
Immerhin programmier ich nun doch schon etwas länger und mir hat noch nie jemand gesagt, das ich nen schlechten Stil hätte (also weder mein Informatik Lehrer im Abitur noch jemand hier im Forum, immerhin müsste das doch auffallen.).
Was Informatiklehrer angeht, haben die relativ häufig einen C++-Stil von vor 15 Jahren - was der Sprache und den Erkenntnissen über die Sprache, wie man sie anwenden sollte, einfach nicht mehr entspricht. Was deinen Stil hier im Forum angeht, werden wir ein wenig drauf achten und dich ggf. auf etwaigen JW-Stil aufmerksam machen
-
Hmmh schrieb:
seux schrieb:
gefiehl
Lass mich raten, wegen deiner Rechtschreibung hat dich auch noch keiner kritisiert, oder
*scnr*
Doch, da schon
Okay, zum Stil, ich poste jetzt mal einen Quellcode von mir, den ich vor nicht allzu langer Zeit angeferigt hab, um Dateien aus dem .obj Wavefront Format ins 3ds Max ASCCII Format zu Konvertieren, um Objekte in den Unreal Editor zu importieren.
Stilistisch Sachen müssten ja beim reinen überfliegen auffallen.
#include <iostream> #include <iomanip> #include <cmath> #include <string> #include <sstream> #include <fstream> #include <vector> using namespace std; void extractFilenameAndPath(string str); void parse(char* file); string fileName, aseFilename, aseFileNamePath; class VERTEX { public: float xPos; float yPos; float zPos; VERTEX(float x, float y, float z) { xPos = x; yPos = y; zPos = z; } VERTEX() {} }; class UV { public: float u; float v; UV(float uP, float vP) { u = uP; v = vP; } UV() {} }; class FACE { public: int A; int B; int C; FACE(int a, int b, int c) { A = a; B = b; C = c; } FACE() {} }; class FACEVT { public: int vt1; int vt2; int vt3; FACEVT(int a, int b, int c) { vt1 = a; vt2 = b; vt3 = c; } FACEVT() {} }; int main(int argc, char *argv[]) { //Programm muss mit Argumenten aufgerufen werden if(argc <= 1) { return 0; } for(int i = 0; i < (argc -1); i++) { ifstream objFile(argv[i+1]); extractFilenameAndPath(argv[i+1]); parse(argv[i+1]); } //Warte auf eingabe vom User int i = 0; cin >> i; return 0; } void extractFilenameAndPath(string str) { //string fileName, aseFilename, aseFileNamePath; fileName = str; int pos = 0; pos = fileName.find_last_of("\\"); aseFileNamePath.append(fileName, 0, pos+1); fileName.erase(0, pos+1); pos = fileName.find_first_of('.'); aseFilename = fileName; aseFilename.erase(pos, 4); aseFilename.append(".ase"); aseFileNamePath.append(aseFilename); cout << "Converting " << fileName << " to " << aseFilename << endl << endl << "Path: " << aseFileNamePath << endl; } void parse(char* file) { // bool bDebug=true; //Ase file variables int MESH_NUMVERTEX = 0; int MESH_NUMFACES = 0; int MESH_NUMTVERTEX = 0; //Data vektoren vector<VERTEX> v(0); vector<FACE> f(0); vector<FACEVT> fvt(0); vector<UV> uv(0); ifstream objFile(file); if(objFile.is_open() != true) { cout << "Sry, I was unable to open the file"; return; } //Top Level Area string topLevel = "*3DSMAX_ASCIIEXPORT\n"; topLevel.append("*COMMENT \"Obj2Ase ASE output, extracted from: ["); topLevel.append(fileName); topLevel.append("]\"\n"); topLevel.append("*MATERIAL_LIST {\n*MATERIAL_COUNT 1\n\t*MATERIAL 0 {\n"); topLevel.append("\t\t*MATERIAL_NAME \"AxToolMultiSubMimicry\"\n\t\t*MATERIAL_CLASS \"Multi/Sub-Object\"\n\t\t*NUMSUBMTLS 1\n"); topLevel.append("\t\t*SUBMATERIAL 0 {\n\t\t\t*MATERIAL_NAME \"initialShadingGroup\"\n\t\t\t*MATERIAL_CLASS \"Standard\"\n\t\t\t*MAP_DIFFUSE {\n\t\t\t\t*MAP_CLASS \"Bitmap\"\n\t\t\t\t*BITMAP \"None\""); topLevel.append("\n\t\t\t\t*UVW_U_OFFSET 0.0\n\t\t\t\t*UVW_V_OFFSET 0.0\n\t\t\t\t*UVW_U_TILING 1.0\n\t\t\t\t*UVW_V_TILING 1.0"); topLevel.append("\n\t\t\t}\n\t\t}\n\t}\n}"); //cout << topLevel; //Debug //Geometry Area string geomitryObject = ("*GEOMOBJECT {\n\t*NODE_NAME \""); geomitryObject.append(aseFilename); geomitryObject.append("\"\n\t*NODE_TM {\n"); geomitryObject.append("\t*NODE_NAME \""); geomitryObject.append(aseFilename); geomitryObject.append("\"\n\t}\n\t*MESH {\n\t\t*TIMEVALUE 0"); //cout << geomitryObject; //Debug char fileData[128] = {0}; string MeshVertexList; MeshVertexList.clear(); string MeshTVertList; MeshTVertList.clear(); string MeshFaceList; MeshFaceList.clear(); string MeshNumTVFacesList; MeshNumTVFacesList.clear(); //Zeilenweise die Datei abarbeiten while(!objFile.eof()) { objFile.getline(fileData, 128); //Vertex found if(fileData[0] == 'v' && fileData[1] == ' ') { stringstream sstr; string dataLine(fileData); //Vertex coord search engine { int iFirstPos = 0; VERTEX tmp; string coord; iFirstPos = dataLine.find_first_of(' '); dataLine.erase(0, iFirstPos+1); //X-Koordinate iFirstPos = dataLine.find_first_of(' '); coord.clear(); coord.append(dataLine, 0, iFirstPos); sstr.clear(); sstr << coord; sstr >> tmp.xPos; dataLine.erase(0, iFirstPos+1); //Y-Koordinate iFirstPos = dataLine.find_first_of(' '); coord.clear(); coord.append(dataLine, 0, iFirstPos); sstr.clear(); sstr << coord; sstr >> tmp.yPos; dataLine.erase(0, iFirstPos+1); //Z-Koordinate iFirstPos = dataLine.find_first_of(' '); coord.clear(); coord.append(dataLine, 0, iFirstPos); sstr.clear(); sstr << coord; sstr >> tmp.zPos; dataLine.erase(0, iFirstPos+1); //Strinstream leeren sstr.str(""); sstr.clear(); v.push_back(VERTEX(tmp.xPos, tmp.yPos, tmp.zPos)); } } //UV Koordinaten if(fileData[0] == 'v' && fileData[1] == 't') { stringstream sstr; UV tmp; string dataLine = fileData; dataLine.erase(0, 3); int iFirstPos = 0; string uvCoord = ""; iFirstPos = dataLine.find_first_of(' '); uvCoord = dataLine.substr(0, iFirstPos); sstr << uvCoord; sstr >> tmp.u; dataLine = dataLine.erase(0, iFirstPos +1); sstr.str(""); sstr.clear(); iFirstPos = dataLine.find_first_of(' '); uvCoord = dataLine.substr(0, iFirstPos); sstr << uvCoord; sstr >> tmp.v; sstr.str(""); sstr.clear(); uv.push_back(UV(tmp.u, tmp.v)); } //Faces if(fileData[0] == 'f' && fileData[1] == ' ') { stringstream sstr; string s = ""; FACE fTmp; FACEVT fvTmp; string dataLine = fileData; dataLine.erase(0, 2); int iFirstPos = 0; //Punt A iFirstPos = dataLine.find_first_of('/'); s = dataLine.substr(0, iFirstPos); sstr << s; sstr >> fTmp.A; sstr.str(""); sstr.clear(); dataLine.erase(0, iFirstPos +1); iFirstPos = dataLine.find_first_of(' '); s = dataLine.substr(0, iFirstPos); sstr << s; sstr >> fvTmp.vt1; sstr.str(""); sstr.clear(); dataLine.erase(0, iFirstPos +1); //Punkt B iFirstPos = dataLine.find_first_of('/'); s = dataLine.substr(0, iFirstPos); sstr << s; sstr >> fTmp.B; sstr.str(""); sstr.clear(); dataLine.erase(0, iFirstPos +1); iFirstPos = dataLine.find_first_of(' '); s = dataLine.substr(0, iFirstPos); sstr << s; sstr >> fvTmp.vt2; sstr.str(""); sstr.clear(); dataLine.erase(0, iFirstPos +1); //Punkt C iFirstPos = dataLine.find_first_of('/'); s = dataLine.substr(0, iFirstPos); sstr << s; sstr >> fTmp.C; sstr.str(""); sstr.clear(); dataLine.erase(0, iFirstPos +1); iFirstPos = dataLine.find_first_of(' '); s = dataLine.substr(0, iFirstPos); sstr << s; sstr >> fvTmp.vt3; sstr.str(""); sstr.clear(); f.push_back(FACE(fTmp.A, fTmp.B, fTmp.C)); fvt.push_back(FACEVT(fvTmp.vt1, fvTmp.vt2, fvTmp.vt3)); } } //Data vektoren in strings umwandeln //Vertex: for(size_t i = 0; i < v.size(); i++) { stringstream sstr; //Axen sind nicht gleich sstr << "\t\t\t*MESH_VERTEX" << setw(5) << MESH_NUMVERTEX++ << "\t"; sstr.precision(5); //sstr << fixed << setw(9) << v.xPos << "\t" << setw(9) << v.yPos << "\t" << setw(9) << v.zPos << "\n"; //Koordinatensystem korrektion sstr << fixed << setw(9) << (v[i].xPos * -1) << "\t" << setw(9) << v[i].zPos << "\t" << setw(9) << v[i].yPos << "\n"; MeshVertexList.append(sstr.str()); } //Faces for(size_t i = 0; i < f.size(); i++) { stringstream sstr; sstr << "\t\t\tMESH_FACE" << setw(5) << MESH_NUMFACES++ << ": A:" << setw(5) << f[i].A -1 << " B:" << setw(5) << f[i].B -1 << " C:" << setw(5) << f[i].C -1 << "\t\t*MESH_SMOOTHING 0 *MESH_MTLID 0" << endl; MeshFaceList.append(sstr.str()); } //UV's int iCount = 0; for(size_t i = 0; i < f.size(); i++) { stringstream sstr; sstr.precision(0); sstr << "\t\t\t*MESH_TVERT " << iCount++ << "\t"; sstr.precision(6); sstr << fixed << uv[fvt[i].vt1-1].u << "\t" << uv[fvt[i].vt1-1].v << "\t0.000000" << endl; MeshTVertList.append(sstr.str()); sstr.str(""); sstr.clear(); sstr.precision(0); sstr << "\t\t\t*MESH_TVERT " << iCount++ << "\t"; sstr.precision(6); sstr << fixed << uv[fvt[i].vt2-1].u << "\t" << uv[fvt[i].vt2-1].v << "\t0.000000" << endl; MeshTVertList.append(sstr.str()); sstr.str(""); sstr.clear(); sstr.precision(0); sstr << "\t\t\t*MESH_TVERT " << iCount++ << "\t"; sstr.precision(6); sstr << fixed << uv[fvt[i].vt3-1].u << "\t" << uv[fvt[i].vt3-1].v << "\t0.000000" << endl; MeshTVertList.append(sstr.str()); sstr.str(""); sstr.clear(); } int iCounter = 0; for(int i = 0; i < MESH_NUMFACES; i++) { stringstream sstr; sstr << "\t\t\t*MESH_TFACE " << i << "\t" << iCounter++ << "\t" << iCounter++ << "\t" << iCounter++ << endl; MeshNumTVFacesList.append(sstr.str()); } //In eine Datei ausgeben //ofstream aseFile("C:/Users/User/Eigene Programme/Obj2Ase Converter/bin/Debug/BasicSphere.ase"); ofstream aseFile(aseFileNamePath.c_str()); if(aseFile.is_open() != true) { cout << "Ase file nicht erzeugt."; return; } aseFile << topLevel << endl << geomitryObject << endl; //MeshVertexList schreiben aseFile << "\t\t*MESH_NUMVERTEX " << MESH_NUMVERTEX << endl; aseFile << "\t\t\t*MESH_NUMFACES " << MESH_NUMFACES << endl; aseFile << "\t\t*MESH_VERTEX_LIST {" << endl; aseFile << MeshVertexList << "\t\t}" << endl; //MeshFaceList schreiben aseFile << "\t\t*MESH_FACE_LIST {" << endl; aseFile << MeshFaceList; aseFile << "\t\t}" << endl; //MeshTVertList schreiben MESH_NUMTVERTEX = 3*f.size(); aseFile << "\t\t*MESH_NUMTVERTEX " << MESH_NUMTVERTEX << endl; aseFile << "\t\t*MESH_TVERTLIST {" << endl; aseFile << MeshTVertList; aseFile << "\t\t}" << endl; //MeshNumTVfaces aseFile << "\t\t*MESH_NUMTVFACES " << MESH_NUMFACES << endl; aseFile << "\t\t *MESH_TFACELIST {" << endl; aseFile << MeshNumTVFacesList; aseFile << "\t\t}" << endl; //Ending aseFile << "\t}" << endl << "\t*MATERIAL_REF 0" << endl << "}" << endl; }
-
Da weiß man gar nicht wo man anfangen soll. Und ich dachte, ein Buch kann doch gar nicht so schlimm sein.
9: globales namespace std;
11: string per value übergeben
12: char* ist nicht const. Und dann noch inkonsistent was die Verwendung von const char* bzw. const std::string& angeht.
13: Globale Variablen
- Für alles eine Eigene Klasse, obwohl ein template vec3 reichen würde.Gott, wenn ich so nach unten scrolle, habe ich jetzt schon keine Lust mehr weiter zu machen. Räum da erst mal auf.
Edit: Und ich habe mich noch darüber gewundert, dass hier einige "ganz lesen" vorgeschlagen haben..
-
Ich muß erstmal ein Viertelstündchen weinen. Bin bald wieder (geschwächt) da. Macht sowas besser nicht jeden Tag.
-
cooky451 schrieb:
9: globales namespace std;
Ist in dem Fall kein Problem. Die restlichen Kommentare stimmen aber.
weiteres zum Code:
15: Klassennamen ausschließlich in Großbuchstaben zu schreiben ist unkonventionell (d.h. für jeden anderen irritierend), sowas ist normalerweise #defines und evtl. enum-werten vorbehalten
18: Membervariablen sollten grundsätzlich private sein.
22: benutze Initialisierungslisten, um Membervariablen in Konstruktoren Werte zuzuweisen.
28: vermeide default-Konstruktoren, wenn sie nicht sinnvoll sind. D.h. schreibe sie nicht nur um Kompilerfehler zu beseitigen.
80: Wo ist die Fehlermeldung? Über ein Programm dass sich kommentarlos beendet freut sich niemand.
11/102: Statt globaler Variablen sollten deine Funktionen Ergebnisse zurückgeben.
123: 340 Zeilen für ein Funktion ist definitiv zu lang, das solltest du sinnvoll aufsplitten.
128: definiere Variablen dort wo du sie brauchst, nicht wie in C am Anfang der Funktion
170: neu erstellte strings sind immer leer, die brauchst du nicht zu clearen.
182/184: while (getline(filedata,128)) {...}
203/215/227: Code duplication, google: DRY-Prinzip
242: Du brauchst kein temporäres Objekt zu konstruieren, um es per push_back an den vector zu geben. push_back(tmp) reicht hier.
261/272: DRY
391/399/407: DRY
Das war das, was mir beim ersten Überfliegen so aufgefallen ist. Die Fehler bzw. der schlechte Stil wiederholen sich an zig Stellen.
Überleg mal, ob du das, was deine parse-Funktion machen soll, in wenigen Schritten (schaffst du es unter 10?) beschreiben kannst. Das ist dann Grundlage für eine Funktion. Die einzelnen Schritte sind jeweils wieder eine Funktion, die du in unterschritte aufteilst usw.
-
pumuckl schrieb:
cooky451 schrieb:
9: globales namespace std;
Ist in dem Fall kein Problem.
Ich wollte noch etwas zur Aufteilung in Dateien schreiben, aber als ich dann nach unten gescrollt habe, habe ich zu viel Angst bekommen.
-
gcc schrieb:
test.cpp: In function ‘void parse(char*)’:
test.cpp:420:116: warning: operation on ‘iCounter’ may be undefinedhm...
sstr << "\t\t\t*MESH_TFACE " << i << "\t" << iCounter++ << "\t" << iCounter++ << "\t" << iCounter++ << endl;
Da hat er recht.