好的,请原谅我凌乱的代码。下面是我的队列类。
#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;
它会为我提供奇怪的值,如.. 7.86914e-316。
非常感谢帮助!
答案 0 :(得分: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 :(得分:1)
我没有在那里看到赋值运算符,这意味着您将获得编译器生成的默认值,这将执行浅拷贝。您可能需要自己提供深度复制。你的评论所谓的副本ctor也不是真正的副本。复制ctor 总是对正在复制的对象进行const引用,因此签名将是:
Queue(Queue const &original);
。
答案 2 :(得分:1)
您需要一个合适的赋值运算符。您的示例可能无法按照您提供课程的方式进行编译。
即使我错了,代码中的主要错误是你的operator=
称它为自己的析构函数。这是非常错误的。析构函数稍后也会被称为“自然”。这意味着您的对象将被删除两次。 (因为您没有在析构函数中为Queue.myFront指定NULL。)
Don't manually call destructors.
对于基本练习,我建议您在第qdub2 = qdub1
行上放置一个断点,然后逐步调试以查看您的代码真正做了什么。
答案 3 :(得分:0)
根据一般编码标准,您不应该致电
this->~Queue()
通过这个语句,一个对象试图删除自己。 尝试将数据复制到新队列中,如果超出范围则将其删除。否则保持不变。
另一个example用于理解C ++模板