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;
    };
    
    #endif
    

    antworten.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: $?"}
                           };
    
    #endif
    

    bindungen.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}
                           };
    
    #endif
    

    phrasen.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?" }
                           };
    
    #endif
    

    stichwoerter.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}
                     };
    
    #endif
    

    funktionen.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);
    
    #endif
    

    Ja, 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 status
    

    Das 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: $?"}
                           };
    
    #endif
    

    Das 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.


Anmelden zum Antworten