2010-04-20 41 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++模板