2010-01-15 12 views
2

J'essaie d'imprimer le contenu de la carte et c'est là que mon code échoue. J'ai testé toutes mes méthodes et je n'ai aucun problème à lire à partir du fichier, filer le mot, le mettre dans la carte, et même la fonction d'impression fonctionne. Cependant, lorsque j'appelle la fonction d'impression de la machine principale, elle n'imprime pas la carte. Je suis nouveau au polymorphisme et je pense que mon erreur est dans la façon dont je passe la carte à la fonction principale.Problème C++ lors de l'appel d'une fonction dans main qui imprime la carte

Voici ma classe principale:

using namespace std; 
#include <iostream> 
#include "ReadWords.h" 
#include "ReadPunctWords.h" 
#include "ReadNumWords.h" 
#include "ReadCapWords.h" 
#include "MapWorks.h" 
#include <fstream> 
#include <string> 
#include <map> 
#include <iterator> 

/** 
* This main function uses all other classes. 
*/ 
int main() { 


    char* name = "RomeoJuliet.txt"; 
    //ReadPunctWords &obj = *new ReadPunctWords(name); 
    ReadPunctWords obj(name); 
    string startSearch="BEGIN"; 
    string endSearch="FINIS"; 


    ReadPunctWords rpw; 
    ReadCapWords rcw; 
    ReadNumWords rnw; 
    MapWorks mw; 

    while(rpw.isNextWord()){ 
     string tempword = obj.getNextWord(); 
     if(tempword == startSearch){ 
      break; 
     } 
    } 
    while(rpw.isNextWord()){ 
     string tempword = obj.getNextWord(); 
     if(tempword == endSearch){ 
      break; 
     } 
     else{ 
       if(rpw.filter(tempword)){ 
        mw.addToMap(tempword, mw.mapPunct); 
       } 

       if(rcw.filter(tempword)){ 
        mw.addToMap(tempword, mw.mapCap); 
       } 

       if(rnw.filter(tempword)){ 
        mw.addToMap(tempword, mw.mapNum); 
       } 
      } 
    } 


    mw.printMap(mw.mapPunct); 
    mw.printMap(mw.mapCap); 
    mw.printMap(mw.mapNum); 


    //clear map 
    mw.clearMap(mw.mapPunct); 
    mw.clearMap(mw.mapCap); 
    mw.clearMap(mw.mapNum); 

    //close the file 
    //obj.close(); 


    //delete &obj; 

    //exit(0); // normal exit 
    return 0; 

} 

Et mon MapWorks.cpp qui contient les cartes et les fonctions liées aux cartes:

using namespace std; 
#include <iostream> 
#include <string> 
#include <map> 
#include <iterator> 
#include "MapWorks.h" 

/** 
* MapWorks class builds the maps and does the map processing and printing 
*/ 


MapWorks::MapWorks() {} 

void MapWorks::addToMap(string myword, map<string, int> & myMap){ 
    int n = myMap[myword]; 
    myMap[myword]= n+1; 
} 


void MapWorks::printMap (map<string, int> &myMap){ 

    for (map<string, int>::iterator it = myMap.begin(); it != myMap.end(); ++it) 
    { 
     cout << it->first << " ==> " << it->second << '\n'<<endl; 
    } 
} 


//delete entries in map 
void MapWorks::clearMap(map<string, int>myMap) { 
    myMap.clear(); 

} 

MapWorks.h:

#ifndef MAPWORKS_H 
#define MAPWORKS_H 
#include <string> 
#include <map> 
using namespace std; 


/** 
* MapWorks class builds the maps and does the map processing and printing 
*/ 

class MapWorks { 
    public: 

    map<string, int> mapPunct; //(word, number of occurences) 
    map<string, int> mapNum; //(word, number of occurences) 
    map<string, int> mapCap; //(word, number of occurences) 

    MapWorks(); 

    void addToMap(string myword, map<string, int> & myMap); //adds words to a map 

    void printMap (map<string, int> &myMap); //prints the map 

    void clearMap(map<string, int>); //clear map 
}; 

#endif 

Mon ReadWords.h:

/** 
* ReadWords class, the base class for ReadNumWords, ReadPunctWords, ReadCapWords 
*/ 

#ifndef READWORDS_H 
#define READWORDS_H 

using namespace std; 
#include <string> 
#include <fstream> 
#include<iostream> 

class ReadWords 
{ 
    private: 
    string nextword; 
    ifstream wordfile; 
    bool eoffound; 

    public: 
    /** 
    * Constructor. Opens the file with the default name "text.txt". 
    * Program exits with an error message if the file does not exist. 
    */ 
    ReadWords(); 

    /** 
    * Constructor. Opens the file with the given filename. 
    * Program exits with an error message if the file does not exist. 
    * @param filename - a C string naming the file to read. 
    */ 
    ReadWords(char *filename); 

    /** 
    * Closes the file. 
    */ 
    void close(); 

    /** 
    * Returns a string, being the next word in the file. 
    * @return - string - next word. 
    */ 
    string getNextWord(); 

    /** 
    * Returns true if there is a further word in the file, false if we have reached the 
    * end of file. 
    * @return - bool - !eof 
    */ 
    bool isNextWord(); 

    //pure virtual function for filter 
    virtual bool filter(string word)=0; 

    /** 
    * Fix the word by the definition of "word" 
    * end of file. 
    * @return - string 
    */ 
    string fix(string word); 
}; 

#endif 

Et mes ReadPunctWords (ReadNumWords et ReadCapWords sont tout à fait la même chose, tout simplement vérifier si le mot a des chiffres ou des lettres majuscules au lieu de ponctuations comme ici):

#ifndef READPUNCTWORDS_H 
#define READPUNCTWORDS_H 
using namespace std; 
#include <string> 
#include "ReadWords.h" 

/** 
* ReadPunctWords inherits ReadWords, so MUST define the function filter. 
* It chooses to override the default constructor. 
*/ 
class ReadPunctWords: public ReadWords { 
    public: 
    ReadPunctWords(); 
    ReadPunctWords(char *filename): ReadWords(filename){}; 
    virtual bool filter(string word); 
}; 

#endif 

Je vous serais reconnaissant de l'aide de vous. Merci, Adriana

+0

(J'aimerais avoir une meilleure façon de formater les commentaires!) –

+0

Merci, je vais essayer de résoudre ce problème et de voir comment c'est. –

+0

Salut, Pouvez-vous y jeter un coup d'oeil? J'ai mis à jour la question et mis en œuvre ces changements. Merci –

Répondre

4

Il y a un certain nombre de choses qui sont les problèmes potentiels dans votre code, mais la chose la plus évidente qui peut causer le printMap à ne pas fonctionner comme prévu est cette boucle while.

map<string, int>::iterator it = myMap.begin(); 
cout<<"test"<<endl; 
while(it!=myMap.end()){ 
cout<<(*it).first<<" ==> "<<(*it).second<<endl; 
} 

Nulle part incrémenter-vous la iterator donc soit rien ne sera imprimé (si la carte est vide) ou bien le premier élément sera imprimé encore et encore et la boucle ne se terminera pas.

La manière idiomatique d'écrire cette boucle serait une boucle for.

for (std::map<string, int>::iterator it = myMap.begin(); it != myMap.end(); ++it) 
{ 
    std::cout << it->first << " ==> " << it->second << '\n'; 
} 

L'autre problème est que votre fonction addToMap est probablement ne fonctionne pas comme prévu parce que vous passez la carte à la fonction en valeur et cela signifie que la carte que la fonction ajoute un élément à est en fait Lorsque la commande est transmise à la fonction appelante, cette copie est détruite et la carte qui lui a été transmise est toujours vide.

Pour passer une carte par référence, vous devez ajouter & au type du paramètre dans la déclaration de fonction.

c.-à-d.dans le headfile, la définition de la classe MapWorks:

void addToMap(string myword, map<string, int>& myMap); 

et dans le fichier source:

void MapWorks::addToMap(string myword, map<string, int>& myMap) 
{ 
    // definition... 
} 

Votre utilisation de références pour les objets alloués dynamiquement est inhabituel, pour le moins. Pour vos besoins, je ne vois aucun point à faire:

ReadWords &rnw = *new ReadNumWords(); 

lorsque vous supprimez l'objet à la fin de la même fonction dans laquelle il est créé. Vous pouvez juste faire cela (exactement comme vous le faites avec MapWorks mw;).

ReadNumWords rnw; 

Si vous devez utiliser des objets alloués dynamiquement, tout en utilisant des pointeurs plutôt que des références est beaucoup plus courant, mais il est fortement recommandé d'utiliser une sorte de pointeur intelligent de sorte que vous ne devez pas se rappeler d'appeler delete explicitement.

+0

Merci, j'ai fait cela quand j'ai essayé la fonction commentée, et ça ne fonctionnait toujours pas. Pouvez-vous voir autre chose de mal? –

+0

La fonction commentée incrémente un itérateur différent de celui utilisé pour l'impression, de sorte qu'elle est également erronée. Il est difficile de savoir ce qui ne va pas sans voir le reste de votre code source tel que MapWorks.h et Read * Words. *. –

+0

MapWorks.h: #ifndef MAPWORKS_H #define MAPWORKS_H #include #include espace de noms en utilisant std; /** * classe MapWorks construit les cartes et fait le traitement de la carte et l'impression */ MapWorks classe { publics: carte mapPunct; // (mot, nombre d'occurrences) carte mapNum; // (mot, nombre d'occurrences) carte mapCap; // (mot, nombre d'occurrences) MapWorks(); void addToMap (chaîne, carte ); // ajoute des mots à une carte void printMap (map ); // imprime la carte void clearMap (carte ); // effacer la carte }; #endif –

0

Vous avez oublié d'incrémenter iterator:

while(it!=myMap.end()){ 
    cout<<(*it).first<<" ==> "<<(*it).second<<endl; 
    // you forgot this: 
    it++; 
} 

Et, plus important encore, envisager quelques modifications à votre code:

// ReadPunctWords &obj = *new ReadPunctWords(name); 
// should likely be: 
ReadPunctWords obj(name); 
// same applies to other 'newed' 'references' 
// and then there's no need to do 
// delete &obj; 

// exit(0); // normal exit 
// should probably be just a 
return 0; 

// obj.close(); 
// can be called in the destructor of ReadPunctWords class 
// and RAII will help you get your file closed correctly when needed 

// void MapWorks::printMap (map<string, int>myMap) 
// should better be: 
void MapWorks::printMap (const std::map<string, int> &myMap) 
// same applies to other functions in your code 

// here's how your commented-out function could look like 
void MapWorks::printMap(const std::map<string, int> &myMap) { 
    typedef std::map<string, int>::iterator mapsi; 
    for (mapsi m = myMap.begin(); m != myMap.end(); ++m) { 
     std::cout << (*m).first << " ==> " << (*m).second << "\n"; 
    } 
} 

// void MapWorks::addToMap(string myword, map<string, int>myMap) 
// should be: 
void MapWorks::addToMap(std::string myword, std::map<string, int> &myMap) 
+0

Je pense que vous voulez dire: 'ReadPunctWords obj (nom);' ou 'ReadPunctWords * obj = new PunctWords (nom);'. De la description de RAII je présume le premier. –

+0

Je l'ai fait, merci! Cela ne fonctionne toujours pas ... Pouvez-vous repérer autre chose? –

+0

@Charles Bailey, merci. – Dmitry

0

Si possible, je suggérerais de diviser la logique en unités légèrement plus petites, et de pousser plus de logique dans les classes - en ce moment, main fait beaucoup plus que ce que je voudrais voir là, et (en particulier) en sait plus sur les internes des classes que j'aimerais voir non plus.

Si je le faisais, je commencerais avec une carte qui savait comment filtrer les mots, il ne peut accepter ce qu'il est censé:

class Map { 
    std::map<std::string, int> counts; 
public: 
    struct Filter { 
     virtual bool operator()(std::string const &) const = 0; 
    }; 

    Map(Filter const &f) : filter(f) {} 

    bool InsertWord(std::string const &word) { 
     return filter(word) && (++counts[word] != 0); 
    } 

    friend std::ostream &operator<<(std::ostream &os, Map const &m) { 
     std::copy(m.counts.begin(), 
        m.counts.end(), 
        std::ostream_iterator<count>(std::cout, "\n")); 
     return os; 
    } 
private: 
    Filter const &filter; 
}; 

Ensuite, nous aurions besoin des dérivés de Filtre pour faire le vrai filtrage. Ceux-ci ne fonctionnent probablement pas comme vous le voulez vraiment; ils sont vraiment seulement des espaces réservés:

struct Num : Map::Filter { 
    bool operator()(std::string const &w) const { 
     return isdigit(w[0]) != 0; 
    } 
}; 

struct Punct : Map::Filter { 
    bool operator()(std::string const &w) const { 
     return ispunct(w[0]) != 0; 
    } 
}; 

struct Letter : Map::Filter { 
    bool operator()(std::string const &w) const { 
     return isalpha(w[0]) != 0; 
    } 
}; 

Alors MapWorks peut déléguer presque tout le travail réel à la carte (ce qui utilise un filtre):

class MapWorks { 
    Map num; 
    Map punct; 
    Map letter; 
public: 

    // For the moment, these allocations just leak. 
    // As long as we only create one MapWorks object, 
    // they're probably not worth fixing. 
    MapWorks() 
     : num(Map(*new Num())), 
      punct(Map(*new Punct())), 
      letter(Map(*new Letter())) 
    {} 

    // Try adding the word until we find a Map 
    // that accepts it. 
    bool push_back(std::string const &word) { 
     return num.InsertWord(word) 
      || punct.InsertWord(word) 
      || letter.InsertWord(word); 
    } 

    // Write out by writing out the individual Map's: 
    friend std::ostream &operator<<(std::ostream &os, MapWorks const &m) { 
     return os << m.num << "\n" << m.punct << "\n" << m.letter << "\n"; 
    }  
}; 

Avec ceux-ci en place, main devient assez simple: (bien que pour le moment, je viens d'avoir le lire un fichier entier au lieu de chercher « BEGIN » et « FINIS »):

int main() { 
    MapWorks m; 

    std::string temp; 
    while (std::cin >> temp) 
     m.push_back(temp); 

    std::cout << m; 
    return 0; 

} 

il y a quelques autres morceaux, tels que ty pedef'ing le type de compte et définissant un inserter pour lui, mais ils sont des détails mineurs.