Allgemeines Klassen-Verständnis-Problem?
-
Servus zusammen!
Ich dachte bisher eigentlich die Klassen bzw. besser gesagt die Grundlagen der OOP verstanden zu haben.
Dies wiederlegte sich jedoch gestern...
Folgendes:Da sich auf meiner Platte recht viele Mp3's befinden, in denen das ID3-Tag in den Versionen 1.0 und 1.1 benutzt wird, und ich diese Mp3's jetzt ein bisschen ordnen möchte, habe ich hier ein paar Klassen zum Verwalten des Tags geschrieben.
Hier der Grundaufbau der Klassen: (Hoffentlich verständlich)
Tag_versions ID3_tag (Abstrakt) / \ / \ Ist-Beziehung / \ Ist-Beziehung Ist-Bez. / \ Ist-Bez. / \ / \ Tag_version1 Tag_version11 ID3_version1 ID3_version11 | |-------Hat-Beziehung-|------------------| |----- Hat-Beziehung ----------------------|
Kurz gesagt, die Klasse ID3_version1 'handelt' das ID3-Tag in der Version 1.0 (und besitzt ein Datenelement der Klasse Tag_version1) und die Klasse ID3_version11 behandelt das ID3-Tag in der Version 1.1 (besitzt ein Datenelement der Klasse Tag_version11)
Um diese Klassen zu testen habe ich zwei kleine main()-Funktionen geschrieben. Und jetzt meine Frage: Warum machen diese beiden main()-Funktionen nicht das gleiche?. Müssten sie doch eigentlich, oder?
Bei der ersten bekomme ich einen Speicherzugriffsfehler...
1. main()-Funktion: (Hier tritt der Fehler auf)
int main(int argc, char* argv[]) { if(argc != 2) { cout << "\n Usage: id3tag.exe mp3file\n"; return -1; } try { /* Hinweis: Hier ist es übrigens egal, welche Klasse ich zuerst definiere, es wird immer nur der Default-Ctor der zuerst-definierten Klasse aufgerufen, danach tritte der Speicherzugriffsfehler auf. */ ID3_version1 v1; ID3_version11 v11; v1.link(argv[1]); v11.link(argv[1]); v1.read(); v11.read(); const Tag_versions* tag1 = v1.gettag(); const Tag_versions* tag11 = v11.gettag(); /* Hinweis bzg. Tag_versions:: ... tag ist vom Typ std::vector<std::string>. Ein Enum in der Klasse Tag_versions speichert den jeweiligen Index des vectors in einem aussagekräftigen Namen. */ cout << "\n v1:\n"; cout << "\tArtist: " << tag1 -> tag[Tag_versions::artist] << endl; cout << "\tTitle: " << tag1 -> tag[Tag_versions::title] << endl; cout << "\n v11:\n"; cout << "\tArtist: " << tag11 -> tag[Tag_versions::artist] << endl; cout << "\tTitle: " << tag11 -> tag[Tag_versions::title] << endl; } catch(Open_error& o_err) { cout << "\n Couldn't open the file " << o_err.getfilename() << endl; } catch(File_error& f_err) { cout << "\n Unspecified problem with the file " << f_err.getfilename() << endl; } return 0; }
2. main()-Funktion: (Hier tritt _kein_ Fehler auf)
int main(int argc, char* argv[]) { if(argc != 2) { cout << "\n Usage: id3tag.exe mp3file\n"; return -1; } try { ID3_version1 v1; v1.link(argv[1]); v1.read(); const Tag_versions* tag1 = v1.gettag(); cout << "\n v1:\n"; cout << "\tArtist: " << tag1 -> tag[Tag_versions::artist] << endl; cout << "\tTitle: " << tag1 -> tag[Tag_versions::title] << endl; ID3_version11 v11; v11.link(argv[1]); v11.read(); const Tag_versions* tag11 = v11.gettag(); cout << "\n v11:\n"; cout << "\tArtist: " << tag11 -> tag[Tag_versions::artist] << endl; cout << "\tTitle: " << tag11 -> tag[Tag_versions::title] << endl; } catch(Open_error& o_err) { cout << "\n Couldn't open the file " << o_err.getfilename() << endl; } catch(File_error& f_err) { cout << "\n Unspecified problem with the file " << f_err.getfilename() << endl; } return 0; }
(Ich hoffe, dass ich euch mit diesem längeren Post nicht 'erschlagen' habe ;); Schonmal vielen Danke fürs durchlesen!)
Vielleicht könnt ihr mir anhand dieses Auschnittes schon sagen, was der Fehler ist. Ansonsten werde ich wohl den weiteren relevanten Code posten müssen, ich weiß nämlich überhaupt nicht wo der Fehler liegt...Caipi
-
Ich hab da eigentlich jetzt keinen Fehlergefunden.
Könnte sein das der Fehler in deinen anderen Klassen liegt.
z.b. wird versucht auf die datei zuzugreifen (mp3) aber sie ist schon offen oder sowas in der richtung.MfG
-
@Evillisimo:
Danke für deine Antwort, jedoch habe ich einen (eventuell) wichtigen Hinweis zum Fehler vergessen nochmal hervorzuheben.Der Speicherzugriffsfehler tritt nach dem Aufruf des ersten Standard-Konstruktors auf. Und in diesem wird die Klasse nicht mit irgendetwas verbunden.
Hier der Code, der relevant ist für einen Aufruf des Default-Ctor's der Klasse ID3_version1 (ID3_version11 ist fast identisch)
ID3_version1::ID3_version1() { } ID3_tag::ID3_tag() : filename(""), filesize(0) { } Tag_version1() : Tag_versions(7) { init_tag(); } Tag_versions(const unsigned int s) : size(s), tag(size), element_len(size) { } // Und die init_tag()-Funktion. Definiert in der Klasse Tag_version1 und Tag_version11 void init_tag() { element_len[0] = 3; element_len[1] = 30; element_len[2] = 30; element_len[3] = 30; element_len[4] = 4; element_len[5] = 30; element_len[6] = 1; }
Der Aufruf in Worten:
Zuerst wird der Default-Ctor der Klasse ID3_version1 aufgerufen. Dort wird (automatisch) der Ctor der Klasse ID3_tag aufgerufen. Danach geht es wieder in den Default-Ctor von ID3_version1 zurück. Es wird der Default-Ctor für die Klasse Tag_version1 aufgerufen und in diesem der Ctor von Tag_versions. Danach geht es zurück in den Default-Ctor von Tag_version1 eins, der Rumpf wird ausgeführt. Dann geht es wieder komplett zurück in den Default-Ctor von ID3_version1. Fertig.Vielleicht könnt ihr mir ja mit dieser zusätzlichen Information noch weiterhelfen.
Caipi
-
Scheinbar sind meine Infos immer noch zu rar. (Habe den Thread auch ein wenig einschlafen lassen bzg. Schule etc.)
Hier also ein bisschen mehr Code: (Die Exception-Klassen lasse ich mal weg, da ich dort den Fehler überhaupt nicht vermute)
Es wäre super, wenn ihr einfach mal dem Standard-Konstruktor-Aufruf folgen könntet. (Bei diesem hapert es bei mehreren Instanzen verschiedener oder gleicher Klassen) und dem zweiten Ctor-Aufruf. (Bei diesem funktioniert alles wie gewünscht [zumindest habe ich dort keinen Fehler bemerkt]). Siehe dazu eventuell auch die beiden code-snippets aus meinem ersten Post.tag_versions.h
#ifndef TAG_VERSIONS_H #define TAG_VERSIONS_H #include <string> #include <vector> /* * Format of the ID3 Tag Version 1.0: * offset | length | description * --------------------------------------------- * 0 | 3 | "Tag" identifier string. * 3 | 30 | Song title string. * 33 | 30 | Artist string. * 63 | 30 | Album string. * 93 | 4 | year string. * 97 | 30 | comment string. * 127 | 1 | Genre byte. * * * Format of the ID3 Tag Version 1.1: * offset | length | description * --------------------------------------------- * 0 | 3 | "Tag" identifier string. * 3 | 30 | Song title string. * 33 | 30 | Artist string. * 63 | 30 | Album string. * 93 | 4 | year string. * 97 | 28 | comment string. * 125 | 1 | Zero byte seperator. * 126 | 1 | Track byte. * 127 | 1 | Genre byte. */ class Tag_versions { public: enum Key { id, title, artist, album, year, comment, seperator, track, genre }; std::vector<std::string> tag; std::vector<unsigned int> element_len; // Saves the length of every element from the tag. const unsigned int size; Tag_versions(const unsigned int s) : size(s), tag(size), element_len(size) { std::cout << "\n Ctor Tag_versions\n"; } }; class Tag_version1 : public Tag_versions { public: Tag_version1() : Tag_versions(7) { std::cout << "\n Ctor Tag_version1\n"; std::cout << " size: " << size << std::endl; init_tag(); } void init_tag() { element_len[0] = 3; element_len[1] = 30; element_len[2] = 30; element_len[3] = 30; element_len[4] = 4; element_len[5] = 30; element_len[6] = 1; } }; class Tag_version11 : public Tag_versions { public: Tag_version11() : Tag_versions(9) { std::cout << "\n Ctor Tag_version11\n"; init_tag(); } void init_tag() { element_len[0] = 3; element_len[1] = 30; element_len[2] = 30; element_len[3] = 30; element_len[4] = 4; element_len[5] = 28; element_len[6] = 1; element_len[7] = 1; element_len[8] = 1; } }; #endif // TAG_VERSIONS_H
id3_tag.h
#ifndef ID3_TAG_H #define ID3_TAG_H #include <iostream> #include <fstream> #include "tag_versions.h" #include "id3_tag_exceptions.h" class ID3_tag { protected: std::string filename; std::ifstream filestream; unsigned int filesize; public: ID3_tag(); ID3_tag(const std::string& fn); virtual ~ID3_tag(); void link(const std::string& fn) throw(Open_error, Read_error); virtual void read() throw(File_error) = 0; virtual const Tag_versions* gettag() const = 0; }; // Handles the id3-tag in the version 1.0 class ID3_version1 : public ID3_tag { private: Tag_version1 mytag; public: ID3_version1(); ID3_version1(const std::string& fn); virtual void read() throw(File_error); virtual const Tag_versions* gettag() const; }; // Handles the id3-tag in the version 1.1 class ID3_version11 : public ID3_tag { private: Tag_version11 mytag; public: ID3_version11(); ID3_version11(const std::string& fn); virtual void read() throw(File_error); virtual const Tag_versions* gettag() const; }; #endif // ID3_TAG_H
id3_tag.cpp
#include "id3_tag.h" // Definitions of the Base-class ID3_tag::ID3_tag() : filename(""), filesize(0) { std::cout << "\n Ctor ID3_tag\n"; } ID3_tag::ID3_tag(const std::string& fn) : filename(fn) { link(filename); } ID3_tag::~ID3_tag() { filestream.close(); } void ID3_tag::link(const std::string& fn) throw(Open_error, Read_error) { filename = fn; if(filestream.is_open()) filestream.close(); filestream.open(filename.c_str(), std::ios::binary); if(!filestream.is_open()) { Open_error o_err(filename); filestream.clear(); throw o_err; } filestream.seekg(0L, std::ios::end); if(!filestream.good()) { Read_error r_err(filename); throw r_err; } filesize = filestream.tellg(); } // Definitions of the first derived class ID3_version1::ID3_version1() { std::cout << "\n Ctor ID3_version1\n"; } ID3_version1::ID3_version1(const std::string& fn) : ID3_tag(fn) { } // // Weitere Implementationen der Methoden (imho hier aber unrelevant) // // Definitions of the second derived class ID3_version11::ID3_version11() { std::cout << "\n Ctor ID3_version11\n"; } ID3_version11::ID3_version11(const std::string& fn) : ID3_tag(fn) { } // // Weitere Implementationen ... //
Ich hoffe nicht irgendjemanden überrant oder vor den Kopf gestoßen zu haben. (Bzg des Code-Umfangs).
Caipi
-
Kann mir denn keiner helfen
(*push-it-again-for-the-last-time*)
Caipi
-
ich tippe mal darauf:
die Reihenfolge der Initialisierungen hängt von der Reihenfolge der Deklarationen (in der Klasse) ab.
Du initialisiert size() zwar in der initliste als erstes, hast es aber als letztes in der definition der klasse stehen.
ansonsten:
schalte mal den debugger ein, dann kannst du genau die zeile rausfinden, in der das programm abstürtzt.
-
Shade Of Mine schrieb:
ich tippe mal darauf:
die Reihenfolge der Initialisierungen hängt von der Reihenfolge der Deklarationen (in der Klasse) ab.
Du initialisiert size() zwar in der initliste als erstes, hast es aber als letztes in der definition der klasse stehen.
Super! Es funktioniert!
Oh man, da hätte ich den Fehler jetzt überhaupt nicht vermutet. Diese Regel kannte ich noch garnicht. Ich weiß garnicht wie ich dir danken soll...
(Ich wusste es doch, ein allgemeines Initialisierer-Problem [...] :))Trotzdem würde es mich interessieren warum es bei der einen main-Funktion funktioniert. Ich müsste doch undefiniertes Verhalten erzeugt haben, oder?
Shade Of Mine schrieb:
ansonsten:
schalte mal den debugger ein, dann kannst du genau die zeile rausfinden, in der das programm abstürtzt.Das habe ich bereits, ohne Erfolg. Liegt aber höchstwahrscheinlich daran, dass ich mit dem Debugger (der aus Der Dev-C++ IDE) nicht klarkomme.
Kennt dazu vielleicht jemand ein gutes Tutorial?Caipi