2010-01-15 2 views
2

Я пытаюсь распечатать содержимое карты, и это то, где сбой моего кода. Я тестировал все свои методы, и у меня нет проблем с чтением из файла, фильтрацией слова, его помещением в карту и даже функцией печати. Однако, когда я вызываю функцию принтера из main, она не печатает карту. Я новичок в полиморфизме, и я думаю, что моя ошибка заключается в том, как я передаю карту функции в main.Проблема C++ при вызове функции в главном, которая печатает карту

Вот мой основной класс:

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; 

} 

И мой MapWorks.cpp, который содержит карты и функции, связанные с картами:

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 

My 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 

И мои ReadPunctWords (ReadNumWords и ReadCapWords совсем то же самое, просто проверить, если слово имеет цифры или заглавные буквы вместо знаков препинания, как здесь):

#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 

Я был бы признателен за любую помощь от вас. Спасибо, Adriana

+0

(Мне жаль, что у нас не было лучшего способа форматировать комментарии!) –

+0

Спасибо, я постараюсь исправить это и посмотреть, как это. – 2010-01-15 22:42:33

+0

Привет, Можете ли вы снова взглянуть на него? Я обновил вопрос и внедрил эти изменения. Спасибо – 2010-01-15 23:15:24

ответ

4

Есть целый ряд вещей, которые являются потенциальными проблемами в вашем коде, но самое очевидное, что может привести к тому, что printMap не будет работать должным образом, это цикл while.

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

Нигде вы увеличиваете итератор так как ничего не будет напечатано (если карта пуста) или же первый элемент будет напечатан снова и снова, и цикл не завершится.

Идиоматический способ написать этот цикл будет как цикл for.

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

Другой вопрос заключается в том, что ваша addToMap функция, вероятно, не работает как задумано, потому что вы передаете карту функции значением и это означает, что отображение, что функция добавления элемента на самом деле копия карты, которая была передана.

Когда управление передается вызывающей функции, эта копия уничтожается, а карта, которая была передана, по-прежнему пуста.

Чтобы передать карту по ссылке, вы должны добавить & в тип параметра в объявлении функции.

i.e.в headfile, то определение MapWorks класса:

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

и в исходном файле:

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

Использование ссылок для динамически выделенных объектов является необычным, чтобы не сказать больше. Для ваших целей, я не вижу смысла делать:

ReadWords &rnw = *new ReadNumWords(); 

при удалении объекта в конце той же функции, в которой он был создан. Вы можете просто сделать это (точно так же, как и с MapWorks mw;).

ReadNumWords rnw; 

Если вы должны использовать динамически выделенные объекты, только с помощью указателей, а не ссылки гораздо больше обычного, но настоятельно рекомендуется использовать какой-то умный указатель, так что вам не нужно помнить, чтобы позвонить delete явно.

+0

Спасибо, я сделал это, когда попытался прокомментировать функцию, и она все еще не работает. Вы не видите ничего другого? – 2010-01-15 22:16:20

+0

Функция с комментариями увеличивает итератор от того, который он использует для печати, поэтому он также ошибочен. Трудно узнать, что еще не так, если не увидеть остальную часть исходного кода, например MapWorks.h и Read * Words. *. –

+0

MapWorks.h: #ifndef MAPWORKS_H #define MAPWORKS_H #include #include с использованием пространства имен станд; /** * MapWorks класс строит карты и делает обработку карты и печать */ класса MapWorks { общественности: карту mapPunct; // (слово, количество вхождений) map mapNum; // (слово, количество вхождений) map mapCap; // (слово, количество вхождений) MapWorks(); void addToMap (строка, карта ); // добавляет слова к карте void printMap (map ); // распечатывает карту void clearMap (map ); // очистить карту }; #endif – 2010-01-15 22:43:33

0

Вы забыли, чтобы увеличить итератор:

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

И, что более важно, рассмотрит несколько модификаций коды:

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

Я думаю, что вы либо имеете в виду: 'ReadPunctWords obj (name);' или 'ReadPunctWords * obj = new PunctWords (name);'. Из описания RAII я предполагаю первое. –

+0

Я сделал это, спасибо! Он все еще не работает, хотя ... Вы можете обнаружить что-нибудь еще? – 2010-01-15 22:18:24

+0

@Charles Bailey, спасибо. – Dmitry

0

Если возможно, я предлагаю разбить логику на несколько меньшие единицы и выдвинуть большую часть логики в классы - прямо сейчас, main делает гораздо больше, чем я хотел бы видеть там, и (особенно) знает больше о внутренних классах, чем я хотел бы видеть.

Если бы я делал это, я хотел бы начать с картой, которая знала, как отфильтровать слова, так что он может принимать только то, что он должен:

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

Тогда мы должны были бы некоторые производные Фильтр для реальной фильтрации. Они, вероятно, не работают так, как вы этого хотите; они действительно только заполнители:

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

Тогда MapWorks может делегировать почти всю реальную работу на карте (которая, в свою очередь, использует фильтр):

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

С этим в месте, main становится довольно просто: (хотя на данный момент, я только что это прочитать весь файл вместо того, чтобы искать «BEGIN» и «Finis»):

int main() { 
    MapWorks m; 

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

    std::cout << m; 
    return 0; 

} 

есть несколько другие биты и куски, такие как ф pedef'ing тип счета и определение вставки для него, но они довольно мелкие детали.

Смежные вопросы