Dateistruktur
-
Header:
#include "klassen.h"
#include "antworten.h"
#include "bindungen.h"
#include "phrasen.h"
#include "stichwoerter.h"
#include "funktionen.h"antwort.cpp, bindungen.cpp, phrasen.cpp und stichwoerter.cpp habe ich in .h-Dateien umgeschrieben, sollte man das machen oder nicht??
In funktionen.cpp habe ich auch all diese Header-Dateien eingefügt.
-
ploib_ schrieb:
antwort.cpp, bindungen.cpp, phrasen.cpp und stichwoerter.cpp habe ich in .h-Dateien umgeschrieben, sollte man das machen oder nicht??
Klares jein. Wenn du Funktionen im Header definierst, bekommst du beim Linken Probleme mit der One Definition Rule (ODR), sobald du den Header mehr als einmal irgendwo einbindest.
Die klassische Lösung ist, die Funktionen im Header nur zu deklarieren und in der .cpp zu definieren, wobei die .cpp den header einbindet (genauso wie deine main.cpp)Kurzes Beispiel:
f.h://nur Deklaration void f(int i);f.cpp:
#include <iostream> #include "f.h" void f(int i) { std::cout << "i: " << i << std::endl; }main.cpp:
#include "f.h" int main() { for (int i = 1; i < 1000; i *= 2) { f(i); } }Zu deiner Fehlermeldung: Heißt die Funktion im Header auch wirklich so wie du sie in der main() buchstabiert hast? Zeig uns ggf. nochmal deinen kompletten Code, wie er jetzt aussieht - ist ja nicht so viel

-
main.cpp:
#include <iostream> #include <string> #include <vector> #include "klassen.h" #include "antworten.h" #include "bindungen.h" #include "phrasen.h" #include "stichwoerter.h" #include "funktionen.h" using namespace std; int main() { string Aussage; while (true) { getline(cin, Aussage); vector<string> Woerter; zerlegeInWoerter(Aussage, Woerter); string Antwort; sucheNachAntwort(Woerter, Antwort); cout << Antwort << endl; } }klassen.h:
#ifndef _EKLASSEN_H_ #define _EKLASSEN_H_ #include <string> class tStichwort { public: std::string Wort; int ID; }; class tAntwort { public: long Aufrufe; std::string Antwort; }; class tBindung { public: long WortID; long AntwortID; }; #endifantworten.h:
#ifndef _EANTWORTEN_H_ #define _EANTWORTEN_H_ #include "klassen.h" tAntwort Antworten[] = { {0, "Dein $ ist Dir sehr wichtig, nicht wahr?" }, {0, "Hättest Du darüber nicht mit Deinem $ sprechen sollen?"}, {0, "Erzähle mehr über die Beziehung zu Deinem $!"}, {0, "Deine $ ist Dir sehr wichtig, nicht wahr?" }, {0, "Hättest Du darüber nicht mit Deiner $ sprechen sollen?"}, {0, "Erzähle mehr über die Beziehung zu Deiner $!"}, {0, "$ ist keine echte Lösung."}, {0, "Es ist nicht gut, mit $ zu leben."}, {0, "Sollte die Welt nicht auf $ verzichten?"}, {0, "Was bedeutet das eigentlich für Dich: $?"} }; #endifbindungen.h:
#ifndef _EBINDUNGEN_H_ #define _EBINDUNGEN_H_ #include "klassen.h" tBindung Bindungen[] = { {1, 0}, {1, 1}, {1, 2}, {2, 3}, {2, 4}, {2, 5}, {3, 6}, {3, 7}, {3, 8}, {1, 9}, {2, 9}, {3, 9} }; #endifphrasen.h:
#ifndef _EPHRASEN_H_ #define _EPHRASEN_H_ #include "klassen.h" tAntwort Phrasen[] = { { 0, "Ich verstehe Deine Zurückhaltung." }, { 0, "Solltest Du nicht offener von Dir reden?" }, { 0, "Was meinst Du ist denn die Ursache von all dem?" }, { 0, "Kannst Du etwas präziser werden?" }, { 0, "Du solltest nicht alles in Dich hineinfressen." }, { 0, "Fühlst Du Dich in dieser Hinsicht unsicher?" } }; #endifstichwoerter.h:
#ifndef _ESTICHWOERTER_H_ #define _ESTICHWOERTER_H_ #include "klassen.h" tStichwort Stichwoerter[] = { {"Bruder", 1}, {"Vater", 1}, {"Sohn", 1}, {"Opa", 1}, { "Freund", 1}, { "Mutter", 2}, {"Schwester", 2}, { "Tochter", 2}, {"Oma", 2}, {"Gewalt", 3}, {"Druck", 3}, {"Schweigen", 3} }; #endiffunktionen.cpp:
#include <iostream> #include <string> #include <vector> #include "klassen.h" #include "antworten.h" #include "bindungen.h" #include "phrasen.h" #include "stichwoerter.h" using namespace std; bool istBuchstabe(char Zeichen) { if (Zeichen>='a' && Zeichen<='z') return true; if (Zeichen>='A' && Zeichen<='Z') return true; // Mit UTF-8 wird das mit den Umlauten nicht so einfach return false; } void zerlegeInWoerter(const string &Satz, vector<string> &Woerter) { int Laenge = Satz.length(); int Pos = 0; int Anfang; Woerter.clear(); while (Pos<Laenge) { while (Pos<Laenge && !istBuchstabe(Satz[Pos])) Pos++; Anfang = Pos; while (Pos<Laenge && istBuchstabe(Satz[Pos])) Pos++; Woerter.push_back(Satz.substr(Anfang, Pos-Anfang)); } } long holeAntwort(long WortID) { long min=999999; long minID = -1; long AntwortID; long MaxBindungen=sizeof(Bindungen)/sizeof(Bindungen[0]); for (long bi=0; bi<MaxBindungen; ++bi) { if (Bindungen[bi].WortID==WortID) { AntwortID = Bindungen[bi].AntwortID; if (min>Antworten[AntwortID].Aufrufe) { minID=AntwortID; min=Antworten[AntwortID].Aufrufe; --Antworten[AntwortID].Aufrufe; } } } return minID; } void ersetzePlatzHalter(string &Antwort, const string &Wort) { unsigned long pos = Antwort.find("$"); if (pos!=string::npos) { Antwort.replace(pos, 1, Wort); } } long holePhrase() { long min=999999; long minID = -1; long MaxPhrasen = sizeof(Phrasen)/sizeof(Phrasen[0]); for (long i=0; i<MaxPhrasen; ++i) { if (min>Phrasen[i].Aufrufe) { minID=i; min=Phrasen[i].Aufrufe; --Phrasen[i].Aufrufe; } } return minID; } void sucheNachAntwort(vector<string> &Woerter, string& Antwort) { long MaxStichwoerter=sizeof(Stichwoerter) /sizeof(Stichwoerter[0]); vector<string>::iterator it; for (it=Woerter.begin(); it!=Woerter.end(); ++it) { for (long wi=0; wi<MaxStichwoerter; ++wi) { if (*it == Stichwoerter[wi].Wort) { long ID = Stichwoerter[wi].ID; long AntwortID = holeAntwort(ID); // Nun sollten wir eine ID haben if (AntwortID>=0) { Antwort = Antworten[AntwortID].Antwort; ersetzePlatzHalter(Antwort, *it); // Diese Antwort etwas zurückstellen Antworten[AntwortID].Aufrufe+=10; // wir gehen mal einfach return; } } } } // Kein Stichwort gefunden. Wir faseln... long AntwortID = holePhrase(); Antwort = Phrasen[AntwortID].Antwort; // Diese Antwort etwas zurückstellen Phrasen[AntwortID].Aufrufe+=10; }funktionen.h:
#ifndef _EKLASSEN_H_ #define _EKLASSEN_H_ bool istBuchstabe(char Zeichen); void zerlegeInWoerter(const string &Satz, vector<string> &Woerter); long holeAntwort(long WortID); void ersetzePlatzHalter(string &Antwort, const string &Wort); long holePhrase(); void sucheNachAntwort(vector<string> &Woerter, string& Antwort); #endifJa, die Namen der Funktionen sind identisch.
-
Hallo,
Fehler kommentiert
#ifndef _EKLASSEN_H_ // Includeguards gleich wie bei klassen.h, include wird damit verhindert. Umbenennen! #define _EKLASSEN_H_ bool istBuchstabe(char Zeichen); void zerlegeInWoerter(const string &Satz, vector<string> &Woerter); //namespace std:: vor string und vector vergessen long holeAntwort(long WortID); void ersetzePlatzHalter(string &Antwort, const string &Wort); long holePhrase(); void sucheNachAntwort(vector<string> &Woerter, string& Antwort); #endif
-
Jetzt bekomme ich diese Fehlermeldung:
/tmp/cccNimqL.o:(.bss+0x0): multiple definition of `Antworten' /tmp/ccTSoNaF.o:(.bss+0x0): first defined here /tmp/cccNimqL.o:(.data+0x0): multiple definition of `Bindungen' /tmp/ccTSoNaF.o:(.data+0x0): first defined here /tmp/cccNimqL.o:(.bss+0x60): multiple definition of `Phrasen' /tmp/ccTSoNaF.o:(.bss+0x60): first defined here /tmp/cccNimqL.o:(.bss+0xa0): multiple definition of `Stichwoerter' /tmp/ccTSoNaF.o:(.bss+0xa0): first defined here collect2: ld returned 1 exit status
-
Ich habe es jetzt gelöst. Vielen Dank für eure Hilfe.
In der main.cpp mussten die includes
#include "antworten.h"
#include "bindungen.h"
#include "phrasen.h"
#include "stichwoerter.h"entfernen.
Ich habe jetzt sehr viel dazugelernt. Danke
-
ploib_ schrieb:
Jetzt bekomme ich diese Fehlermeldung:
/tmp/cccNimqL.o:(.bss+0x0): multiple definition of `Antworten' /tmp/ccTSoNaF.o:(.bss+0x0): first defined here /tmp/cccNimqL.o:(.data+0x0): multiple definition of `Bindungen' /tmp/ccTSoNaF.o:(.data+0x0): first defined here /tmp/cccNimqL.o:(.bss+0x60): multiple definition of `Phrasen' /tmp/ccTSoNaF.o:(.bss+0x60): first defined here /tmp/cccNimqL.o:(.bss+0xa0): multiple definition of `Stichwoerter' /tmp/ccTSoNaF.o:(.bss+0xa0): first defined here collect2: ld returned 1 exit statusDas ist genau das was ich oben mit Verletzung der ODR gemeint habe. Die includes aus der Main zu entfernen behebt nur die Symptome, nicht die Ursache (nämlich, dass du die Funktionen non-inline im Header definiert hast).
Schau dir am Besten mal entsprechende Infos zum Arbeiten mit mehreren Übersetzungseinheiten im Buch deiner Wahl oder im Netz an.
-
Ich verstehe nicht was ich genau in den Header-Dateien falsch gemacht habe.
z.B.:
#ifndef _EANTWORTEN_H_ #define _EANTWORTEN_H_ #include "klassen.h" tAntwort Antworten[] = { {0, "Dein $ ist Dir sehr wichtig, nicht wahr?" }, {0, "Hättest Du darüber nicht mit Deinem $ sprechen sollen?"}, {0, "Erzähle mehr über die Beziehung zu Deinem $!"}, {0, "Deine $ ist Dir sehr wichtig, nicht wahr?" }, {0, "Hättest Du darüber nicht mit Deiner $ sprechen sollen?"}, {0, "Erzähle mehr über die Beziehung zu Deiner $!"}, {0, "$ ist keine echte Lösung."}, {0, "Es ist nicht gut, mit $ zu leben."}, {0, "Sollte die Welt nicht auf $ verzichten?"}, {0, "Was bedeutet das eigentlich für Dich: $?"} }; #endifDas ist keine Funktion

-
ploib_ schrieb:
Das ist keine Funktion

Der von dir gepostete Code verletzt die ODR:
ISO/IEC 14882:2003, Abschnitt 3.2 schrieb:
No translation unit shall contain more than one definition of any variable, function, class type, enumeration type or template.
Die Variable Antworten wird in jeder Übersetzungseinheit definiert, die die entsprechende Header-Datei inkludiert. Entweder deklarierst du Antworten als const oder verschiebst ihre Definition in eine Übersetzungseinheit.
-
pumuckl schrieb:
//nur Deklaration void f(int i);inline vergessen.