2012-09-02 159 views
0

我想在不同的文件中排序不同類型的數字作爲學習練習。我設法使雙打和整數排序正確,但無法得到我自己的類型(排序一副撲克牌)以正確格式。我已設法將其縮小到我的排序功能在讀者類。我收到各種錯誤。我究竟做錯了什麼?或者我錯過了什麼?謝謝大家,我希望我能清楚地解釋我的問題。C++模板和類

我的文件,我的卡創建看起來像......

1 11 (meaning Jack of Diamonds) 

2 8 (meaning 8 of hearts) 

等等

錯誤:

error: no match for 'operator<' in '((Reader)this)->Reader::array[compareIndex] < ((Reader)this)->Reader::array[smallestIndex]'

error: cannot convert 'Card' to 'int' in initialization

error: no match for 'operator=' in '((Reader*)this)->Reader::array[smallestIndex] = temp'

我的代碼

最後,主要

#include <iostream> 
#include "Reader.h" 
#include "Card.h" 

using namespace std; 


int main() { 

    Reader<int> nums; 
    Reader<double> dubs; 
    Reader<Card> cards; 
    int number; 

    do { 

     cout << "Enter 1 if your file contains integers\n" 
      << "Enter 2 if your file contains doubles\n" 
      << "Enter 3 if your file contains Cards:\n" 
      << "Enter a number: "; 
     cin >> number; 

     if (number == 1){ 
      nums.open_IO(); 
      nums.read_array(); 
      nums.sort(); 
      nums.write_array(); 
      nums.close_IO(); 
     } else if (number == 2){ 
      dubs.open_IO(); 
      dubs.read_array(); 
      dubs.sort(); 
      dubs.write_array(); 
      dubs.close_IO(); 
     } else if (number == 3){ 
      cards.open_IO(); 
      cards.read_array(); 
      cards.sort(); 
      cards.write_array(); 
      cards.close_IO(); 
     } 

    } while ((number != 1) && (number != 2) && (number != 3)); 


} 

Reader.h

#ifndef READER_H 
#define READER_H 
#include <string> 
#include <fstream> 
using namespace std; 

template <class rList> 
class Reader { 
public: 
    static const int SIZE = 50; 

     Reader(); 

     bool open_IO(); 

     void close_IO(); 

     bool read_array(); 

     bool write_array(); 

     void sort(); 


private: 
     // Ask for the files 
     void ask_filenames(); 

     rList array[SIZE]; 
     int readSize; 

     // input file names and stream to get the data 
     string readFileName; 
     ifstream inFile; 

     // output file names and stream to get the data 
     string writeFileName; 
     ofstream outFile; 
     bool askedFileNames; 
    }; 

#endif 

#include "Reader.cpp" 

我Reader.Cpp文件

// File: Reader.cpp 
#ifndef READER_CPP 
#define READER_CPP 
#include "Reader.h" 
#include <iostream> 
using namespace std; 

/*************************************************************************** 
* Contructors and modifying functions defined in "Reader.h" 
***************************************************************************/ 


template <class rList> 
Reader<rList>::Reader() { 
    askedFileNames = false; 
    readFileName = ""; 
    writeFileName = ""; 
    readSize = 0; 
    rList empty; 
    for(int i = 0; i<SIZE; i++) array[i]=empty; 
} 

template <class rList> 
bool Reader<rList>::open_IO(){ 
    if(!askedFileNames) ask_filenames(); 

    inFile.open(readFileName.c_str()); //we can't pass a string, we need a char array 
    if(!inFile.is_open()) { 
     return false; 
    } 
    outFile.open(writeFileName.c_str()); 
    if(!outFile.is_open()) { 
     inFile.close(); //inFile opened successfully so it needs to be closed now 
     return false; 
    } 
    return true; 
} 

template <class rList> 
void Reader<rList>::close_IO() { 
    inFile.close(); 
    outFile.close(); 
} 

template <class rList> 
bool Reader<rList>::read_array() { 
    if(inFile.is_open()) { 
     inFile >> readSize; 
     int index = 0; 
     while(!inFile.eof() && index < readSize) { 
      inFile >> array[index++]; //increments index after assigning value 
     } 
     readSize = index; //the input file could have had fewer numbers so set readSize 
     return true; 
    } 
    return false; 
} 

template <class rList> 
bool Reader<rList>::write_array() { 
    if(outFile.is_open()) { 
     outFile << readSize << endl; 
     //don't forget the number indicating the element co 
     int index = 0; 
     while(index < readSize) { 
      outFile << array[index++] << endl; 
     } 
     return true; 
    } 
    return false; 
} 

template <class rList> 
void Reader<rList>::sort() { 
    int startIndex = 0; 
    int compareIndex; 
    int smallestIndex; 
    bool smallerFound; 
    while(startIndex < readSize) { 
     smallestIndex = startIndex; 
     compareIndex = startIndex + 1; 
     smallerFound = false; 
     while(compareIndex < readSize) { //find the smallest value from the starting index 
      if(array[compareIndex] < array[smallestIndex]) { 
       smallestIndex = compareIndex; 
       smallerFound = true; 
      } 
      compareIndex++; 
     } 
     if(smallerFound) { //only swap the values if a smaller value is found 
      int temp = array[startIndex]; 
      array[startIndex] = array[smallestIndex]; 
      array[smallestIndex] = temp; 
     } 
     startIndex++; 
    } 
} 

/*-------------------------------------------------------------- 
    This function asks the user for the filenames. This operation 
    is placed in a separate function because it is called multiple 
    times. 
    --------------------------------------------------------------*/ 
template <class rList> 
void Reader<rList>::ask_filenames() { 
    cout << "Welcome. Please type in the name of the file to read the numbers.\n"; 
    cin >> readFileName; 
    cout << "Thank you. Please type in the name of the file to write the numbers.\n"; 
    cin >> writeFileName; 
    askedFileNames = true; 
} 

#endif 

Card.h

#include <ostream> 
#include <string> 
#include "Reader.h" 

using namespace std; 

class Card{ 
public: 
    static const int SIZE = 50; 
    enum SUIT {clubs, diams, hears, spads }; 
    enum RANK {ace=1, two, thr, fou, fiv, six, sev, eig, nin, ten, jac, que, kin}; 

    Card(); 

    Card(int newSuit, int newRank); 

    void change(int newSuit, int newRank); 

    friend ostream& operator << (ostream& out, Card theCard); 
    friend istream& operator >> (istream& in, Card theCard); 

private: 
    void change_rank(int newRank); 

    void change_suit(int newSuit); 

    string get_rank() const; 

    string get_suit() const; 

    SUIT suit; 
    RANK rank; 


}; 

Card.cpp

#include <iostream> 
#include <string> 
#include "Card.h" 

using namespace std; 

Card::Card() { suit = spads; rank = ace; } 

Card::Card(int newSuit, int newRank) { 
    change(newSuit, newRank); 
} 

void Card::change(int newSuit, int newRank) { 
    change_suit(newSuit); 
    change_rank(newRank); 
} 


ostream& operator << (ostream& out, Card theCard) { 
    out << theCard.get_rank() << " of " << theCard.get_suit(); 
    return out; 
} 

istream& operator >> (istream& in, Card theCard) { 
    int aSuit; 
    int aRank; 

    in >> aSuit >> aRank; 
    return in; 
} 


// private member functions to set the private variables with their 
// corresponding values: integer input -> enumerated type; 
void Card::change_rank(int newRank) { 
    if(newRank == ace) rank = ace; 
    else if(newRank == two) rank = two; 
    else if(newRank == thr) rank = thr; 
    else if(newRank == fou) rank = fou; 
    else if(newRank == fiv) rank = fiv; 
    else if(newRank == six) rank = six; 
    else if(newRank == sev) rank = sev; 
    else if(newRank == eig) rank = eig; 
    else if(newRank == nin) rank = nin; 
    else if(newRank == ten) rank = ten; 
    else if(newRank == jac) rank = jac; 
    else if(newRank == que) rank = que; 
    else if(newRank == kin) rank = kin; 
} 

void Card::change_suit(int newSuit) { 
    if(newSuit == clubs) suit = clubs; 
    else if(newSuit == spads) suit = spads; 
    else if(newSuit == diams) suit = diams; 
    else if(newSuit == hears) suit = hears; 
} 

    // Private member functions to extract the information from the card 
    // class. 
string Card::get_rank() const { 
    if(rank == ace) return "ace"; 
    if(rank == two) return "two"; 
    if(rank == thr) return "three"; 
    if(rank == fou) return "four"; 
    if(rank == fiv) return "five"; 
    if(rank == six) return "six"; 
    if(rank == sev) return "seven"; 
    if(rank == eig) return "eight"; 
    if(rank == nin) return "nine"; 
    if(rank == ten) return "ten"; 
    if(rank == jac) return "jack"; 
    if(rank == que) return "queen"; 
    if(rank == kin) return "king"; 
    return "get_rank: error"; 
} 

string Card::get_suit() const { 
    if(suit == diams) return "D"; 
    if(suit == hears) return "H"; 
    if(suit == spads) return "S"; 
    if(suit == clubs) return "C"; 
    return "get_suit: error"; 
} 
+0

我想這些錯誤也與行號一樣,因此: 您需要重載一些操作符來對它們進行排序,錯誤告訴您,應該在哪裏以及哪些操作符被重載。你正在試圖將卡片轉換爲int,這不能隱式完成,所以你必須明確這樣的轉換。 – Benjamin

+0

胡說八道,我想這是有道理的。自從我編程已經很久了,我已經忘記了如何做到這一點。我到底該怎麼做? – Lindsiria

回答

1

你需要實現一個比較運營商Card

class Card{ 
public: 
    friend bool operator< (const Card &left, const Card &right) { 
    ... 
    } 

和你有一個錯字。

if(smallerFound) { //only swap the values if a smaller value is found 
     int temp = array[startIndex]; 
     array[startIndex] = array[smallestIndex]; 
     array[smallestIndex] = temp; 
    } 

應該

if(smallerFound) { //only swap the values if a smaller value is found 
     rList temp = array[startIndex]; 
     array[startIndex] = array[smallestIndex]; 
     array[smallestIndex] = temp; 
    } 

或者更簡單地說

if(smallerFound) { //only swap the values if a smaller value is found 
     std::swap(array[startIndex], array[smallestIndex]); 
    } 
+0

甚至沒有注意到這個錯誤。謝謝。我想我現在理解了朋友重載功能。謝謝你的一切。 – Lindsiria

2

如果您使用的std::vector<Card>而不是C數組,與您Card重載operator<,你可以得到標準庫爲你洗牌和分類。

vector<T>是一個容器隨附標準庫。這是一個可存儲T類型元素的類模板。 T可以是數字類型,std::string或甚至structclass

這裏是你如何重載低於運營商Card

bool Card::operator<(const Card& other) 
{ 
    return true if this card is smaller than the other card; 
    // You may want to order by rank, then by suit, or vice-versa. 
} 

通過此操作員定義,標準庫的容器和算法現在「知道」如何訂購您Cards

以下是如何使用Cardvector s。

std::vector<Card> deck(52); // Initially sized to 52 elements 
// Populate deck just like you would an array 
deck[0] = Card(diams, ace); 
etc... 

// Sort the deck 
std::sort(deck.begin(), deck.end()); 

// Shuffle the deck 
std::random_shuffle(deck.begin(), deck.end()); 

// Get the 5th card in the deck 
Card fifth = deck[4]; 

std::sort使用快速排序算法,這比你寫冒泡排序快得多(沒有違法:-)。編寫手工製作的數據結構和算法很難實現標準庫提供的功能。編譯器編寫者花費數年完善和調整他們的標準庫實現。

當您使用標準庫容器時,您可以使用一系列標準庫算法。這允許您專注於解決問題,而不是一遍又一遍地重寫相同的基本算法和數據結構。

+0

我計劃在使用向量,一旦我的基本工作。我想盡快了解更多關於載體的信息。謝謝 – Lindsiria

+1

+1好答案。然而,如果你是懶惰的,你*可以*只使用'std :: set '。 – bitmask

+1

@bitmask:你不能洗牌'std :: set ',因爲它是一個關聯容器。 –