2010-04-20 73 views
1

好的,請原諒我的亂碼。以下是我的隊列類。C++隊列模板

#include <iostream> 
using namespace std; 
#ifndef QUEUE 
#define QUEUE 

/*---------------------------------------------------------------------------- 
Student Class 

# Methods # 
Student()    // default constructor 
Student(string, int) // constructor 
display()    // out puts a student 

# Data Members # 
Name     // string name 
Id      // int id 
----------------------------------------------------------------------------*/ 
class Student { 
public: 
    Student() { } 
    Student(string iname, int iid) { 
     name = iname; 
     id = iid; 
    } 
    void display(ostream &out) const { 
     out << "Student Name: " << name << "\tStudent Id: " << id 
      << "\tAddress: " << this << endl; 
    } 

private: 
    string name; 
    int id; 
}; 


// define a typedef of a pointer to a student. 
typedef Student * StudentPointer; 

template <typename T> 

class Queue 
{ 
public: 
    /*------------------------------------------------------------------------ 
    Queue Default Constructor 

    Preconditions: none 
    Postconditions: assigns default values for front and back to 0 

    description: constructs a default empty Queue. 
    ------------------------------------------------------------------------*/ 
    Queue() : myFront(0), myBack(0) {} 


    /*------------------------------------------------------------------------ 
    Copy Constructor 

    Preconditions: requres a reference to a value for which you are copying 
    Postconditions: assigns a copy to the parent Queue. 

    description: Copys a queue and assigns it to the parent Queue. 
    ------------------------------------------------------------------------*/ 
    Queue(const T & q) { 
     myFront = myBack = 0; 
     if(!q.empty()) { 
      // copy the first node 
      myFront = myBack = new Node(q.front()); 
      NodePointer qPtr = q.myFront->next; 
      while(qPtr != NULL) { 
       myBack->next = new Node(qPtr->data); 
       myBack = myBack->next; 
       qPtr = qPtr->next; 
      } 
     } 

    } 
    /*------------------------------------------------------------------------ 
    Destructor 

    Preconditions: none 
    Postconditions: deallocates the dynamic memory for the Queue 

    description: deletes the memory stored for a Queue. 
    ------------------------------------------------------------------------*/ 
    ~Queue() { 
     NodePointer prev = myFront, ptr; 
     while(prev != NULL) { 
      ptr = prev->next; 
      delete prev; 
      prev = ptr; 
     } 
    } 
    /*------------------------------------------------------------------------ 
    Empty() 

    Preconditions: none 
    Postconditions: returns a boolean value. 

    description: returns true/false based on if the queue is empty or full. 
    ------------------------------------------------------------------------*/ 
    bool empty() const { 
     return (myFront == NULL); 
    } 
    /*------------------------------------------------------------------------ 
    Enqueue 

    Preconditions: requires a constant reference 
    Postconditions: allocates memory and appends a value at the end of a queue 

    description: 
    ------------------------------------------------------------------------*/ 
    void enqueue(const T & value) { 
     NodePointer newNodePtr = new Node(value); 
     if(empty()) { 
      myFront = myBack = newNodePtr; 
      newNodePtr->next = NULL; 
     } else { 
      myBack->next = newNodePtr; 
      myBack = newNodePtr; 
      newNodePtr->next = NULL; 
     } 
    } 
    /*------------------------------------------------------------------------ 
    Display 

    Preconditions: requires a reference of type ostream 
    Postconditions: returns the ostream value (for chaining) 

    description: outputs the contents of a queue. 
    ------------------------------------------------------------------------*/ 
    void display(ostream & out) const { 
     NodePointer ptr; 
     ptr = myFront; 

     while(ptr != NULL) { 
      out << ptr->data << " "; 
      ptr = ptr->next; 
     } 
     out << endl; 
    } 
    /*------------------------------------------------------------------------ 
    Front 

    Preconditions: none 
    Postconditions: returns a value of type T 

    description: returns the first value in the parent Queue. 
    ------------------------------------------------------------------------*/ 
    T front() const { 
     if (!empty()) 
      return (myFront->data); 
     else 
     { 
      cerr << "*** Queue is empty -- returning garbage value ***\n"; 
      T * temp = new(T); 
      T garbage = * temp; 
      delete temp; 
      return garbage; 
     } 
    } 
    /*------------------------------------------------------------------------ 
    Dequeue 

    Preconditions: none 
    Postconditions: removes the first value in a queue 
    ------------------------------------------------------------------------*/ 
    void dequeue() { 
     if (!empty()) { 
      NodePointer ptr = myFront; 
      myFront = myFront->next; 
      delete ptr; 
      if(myFront == NULL) 
       myBack = NULL; 

     } else { 
      cerr << "*** Queue is empty -- " 
       "can't remove a value ***\n"; 
      exit(1); 
     } 
    } 
    /*------------------------------------------------------------------------ 
    pverloaded = operator 

    Preconditions: requires a constant reference 
    Postconditions: returns a const type T 

    description: this allows assigning of queues to queues 
    ------------------------------------------------------------------------*/ 
    Queue<T> & operator=(const T &q) { 
    // make sure we arent reassigning ourself 
    // e.g. thisQueue = thisQueue. 
     if(this != &q) { 
      this->~Queue(); 
      if(q.empty()) { 
       myFront = myBack = NULL; 
      } else { 
       myFront = myBack = new Node(q.front()); 
       NodePointer qPtr = q.myFront->next; 
       while(qPtr != NULL) { 
        myBack->next = new Node(qPtr->data); 
        myBack = myBack->next; 
        qPtr = qPtr->next; 
       } 
      } 
     } 
     return *this; 
    } 

private: 
    class Node { 
    public: 
     T data; 
     Node * next; 
     Node(T value, Node * first = 0) : data(value), 
              next(first) {} 

    }; 
    typedef Node * NodePointer; 

    NodePointer myFront, 
       myBack, 
       queueSize; 


}; 

/*------------------------------------------------------------------------ 
join 

Preconditions: requires 2 queue values 
Postconditions: appends queue2 to the end of queue1 

description: this function joins 2 queues into 1. 
------------------------------------------------------------------------*/ 

template <typename T> 
Queue<T> join(Queue<T> q1, Queue<T> q2) { 
    Queue<T> q1Copy(q1), q2Copy(q2); 
    Queue<T> jQueue; 


    while(!q1Copy.empty()) { 
     jQueue.enqueue(q1Copy.front()); 
     q1Copy.dequeue(); 
    } 

    while(!q2Copy.empty()) { 
     jQueue.enqueue(q2Copy.front()); 
     q2Copy.dequeue(); 
    } 
    cout << jQueue << endl; 
    return jQueue; 

} 
/*---------------------------------------------------------------------------- 
Overloaded << operator 

Preconditions: requires a constant reference and a Queue of type T 
Postconditions: returns the ostream (for chaining) 

description: this function is overloaded for outputing a queue with << 
----------------------------------------------------------------------------*/ 
template <typename T> 
ostream & operator<<(ostream &out, Queue<T> &s) { 
    s.display(out); 
    return out; 
} 

/*---------------------------------------------------------------------------- 
Overloaded << operator 

Preconditions: requires a constant reference and a reference of type Student 
Postconditions: none 

description: this function is overloaded for outputing an object of type 
      Student. 
----------------------------------------------------------------------------*/ 
ostream & operator<<(ostream &out, Student &s) { 
    s.display(out); 
} 

/*---------------------------------------------------------------------------- 
Overloaded << operator 

Preconditions: requires a constant reference and a reference of a pointer to 
       a Student object. 
Postconditions: none 

description: this function is overloaded for outputing pointers to Students 
----------------------------------------------------------------------------*/ 
ostream & operator<<(ostream &out, StudentPointer &s) { 
    s->display(out); 
} 
#endif 

現在我遇到了一些問題。其一,當我添加0到隊列,然後我輸出像這樣的隊列..

Queue<double> qdub; 
qdub.enqueue(0); 
cout << qdub << endl; 

這樣的作品,它會輸出0.但舉例來說,如果我修改隊列以任何方式..喜歡..將其分配給不同的隊列..

Queue<double> qdub1; 
Queue<double> qdub2; 
qdub1.enqueue(0; 
qdub2 = qdub1; 
cout << qdub2 << endl; 

它會給我奇怪的值,如0 .. 7.86914e-316。

對此的幫助將不勝感激!

+1

7.86914×10^-316代替零可能是舍入誤差。考慮設置輸出流來爲你舍入值。 – WhirlWind 2010-04-20 21:54:26

+0

如果您入隊1.0,會發生什麼情況? – Robb 2010-04-20 21:55:05

+0

0可以精確地以浮點二進制格式表示,因此不會舍入。 – shoosh 2010-04-20 21:57:22

回答

6

您尚未定義複製構造函數或賦值運算符。你有一個隊列類型的實例,而不是另一個隊列。爲了分配和複製隊列本身,編譯器仍然會使用自動生成的錯誤的東西。

(這可能不解釋特定摘錄的輸出。)

另一件事,是完全錯誤的(即使再次片斷從未調用此功能,或者你會遍佈得到編譯器錯誤的地方):

Queue<T> & operator=(const T &q) { 
// make sure we arent reassigning ourself 
// e.g. thisQueue = thisQueue. 
    if(this != &q) { 
     this->~Queue(); 

調用析構函數明確地這樣,然後去上使用的實例是不允許的。顯式析構函數調用僅與構建新的位置的對象結合在一起。

operator=在拷貝構造函數和交換方法(交換兩個實例之間的內部表示)的條款履行情況正常:

void swap(Queue<T>& rhv) 
{ 
    std::swap(myFront, rhv.myFront); 
    std::swap(myBack, rhv.myBack); 
    std::swap(queueSize, rhv.queueSize); 
} 

Queue<T>& operator=(const Queue<T>& rhv) 
{ 
    Queue<T> copy(rhv); 
    this->swap(copy); 
} //the destructor of copy releases the previous contents of *this 
1

我沒有看到賦值運算符存在,這意味着你獲得編譯器生成的默認值,這將執行淺拷貝。您可能需要提供自己的代碼來進行深層複製。你的評論稱爲複製ctor也不是真正的複製ctor。構造函數總是副本需要一個const對象的引用被複制,所以它的簽名是: Queue(Queue const &original);

1

您需要一個適當的賦值運算符。你的例子可能不會像你提供你的課程那樣編譯。

即使我錯了,在你的代碼的主要錯誤是,你operator=調用它自己的析構函數。這是非常錯誤的。析構函數稍後也會自動調用。這意味着你的對象將被刪除兩次。 (因爲你沒有在你的析構函數分配NULL來Queue.myFront。)

Don't manually call destructors.

對於基本的練習,我建議您將上線qdub2 = qdub1一個斷點,然後一步一步的調試,看看你的代碼真的在做什麼。

0

按照一般的編碼標準,你不應該叫

this->~Queue() 

通過這一聲明的目的是試圖刪除自身。 嘗試將數據複製到新隊列中,然後在超出範圍時將其刪除。否則保持原樣。

另一個example對於理解C++模板