Pergunta

Estou tentando imprimir o conteúdo do mapa e é aqui que meu código falha. Eu testei todos os meus métodos e não tenho nenhum problema para ler do arquivo, arquivar a palavra, colocar -o no mapa e até a função de impressão está funcionando. No entanto, quando estou chamando a função da impressora, ela não imprime o mapa. Sou novo no polimorfismo e acho que meu erro está em como estou passando o mapa para a função em Main.

Aqui está minha aula principal:

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;

}

E meus mapworks.cpp, que contém os mapas e as funções relacionadas aos mapas:

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

Minhas palavras -reads.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

E minhas palavras -readpuncts (readnumwords e readcapwords são iguais, apenas verificando se a palavra tem dígitos ou letras maiúsculas em vez de pontuações como aqui):

#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

Eu apreciaria qualquer ajuda sua. Obrigado, Adriana

Foi útil?

Solução

Existem várias coisas que são problemas em potencial em seu código, mas a coisa mais óbvia que pode estar causando o printMap Não funcionar como o esperado é esse enquanto o loop.

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

Em nenhum lugar você incrementa o iterador para que nada seja impresso (se o mapa estiver vazio) ou o primeiro item será impresso repetidamente e o loop não terá rescisão.

A maneira idiomática de escrever esse loop seria como um loop.

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

A outra questão é que o seu addToMap A função provavelmente não está funcionando como pretendida porque você passa no mapa para a função por valor E isso significa que o mapa para o qual a função está adicionando um item é na verdade uma cópia do mapa que foi passado.

Quando o controle é passado para a função de chamada, essa cópia é destruída e o mapa que foi passado ainda está vazio.

Para passar um mapa por referência, você precisa adicionar & para o tipo do parâmetro na declaração de função.

ou seja, no arquivo de cabeça, o MapWorks Definição de classe:

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

e no arquivo de origem:

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

Seu uso de referências para objetos alocados dinamicamente é incomum, para dizer o mínimo. Para seus propósitos, não vejo nenhum ponto em fazer:

ReadWords &rnw = *new ReadNumWords();

Quando você exclui o objeto no final da mesma função em que é criado. Você pode simplesmente fazer isso (exatamente como você MapWorks mw;).

ReadNumWords rnw;

Se você precisar usar objetos alocados dinamicamente, apenas usar ponteiros em vez de referências é muito mais comum, mas é altamente recomendável usar algum tipo de ponteiro inteligente para que você não precise se lembrar de ligar delete explicitamente.

Outras dicas

Você esqueceu de incrementar o iterador:

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

E, mais importante, considere poucas modificações em seu código:

// 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)

Se possível, sugiro dividir a lógica em unidades um pouco menores e empurrar mais da lógica para as classes - agora, agora, main Faz muito mais do que eu gostaria de ver lá, e (principalmente) sabe mais sobre os internos das aulas do que eu gostaria de ver.

Se eu estivesse fazendo isso, começaria com um mapa que sabia como filtrar as palavras, para que só possa aceitar o que deveria:

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

Em seguida, precisaríamos de alguns derivados de filtro para fazer a filtragem real. Provavelmente não funcionam da maneira que você realmente deseja; Eles são realmente apenas espaços reservados:

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

Em seguida, o MapWorks pode delegar quase todo o trabalho real ao mapa (que por sua vez usa um filtro):

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";
    }       
};

Com estes no lugar, main Torna -se bastante simples: (embora no momento, acabei de ler um arquivo inteiro em vez de procurar "Begin" e "Finis"):

int main() { 
    MapWorks m;

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

    std::cout << m;
    return 0;

}

Existem alguns outros bits, como o Typedef'ing do tipo de contagem e definindo um inseror para isso, mas são detalhes bastante pequenos.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top