重载类模板(链表)中的运算符

Overloading Operators Within a Class Template(Linked List)

本文关键字:运算符 链表 重载      更新时间:2023-10-16

注意:这是家庭作业

具体来说,我的问题是+赋值运算符,我正在编写一个单链列表模板,必须创建运算符+=、+、-、[]等等。我已经编写了数组,到目前为止+=没有太大问题,但现在我正在处理+运算符目前我有。。。

队列.h

#ifndef QUEUE_H
#define QUEUE_H
#include<iostream>
//#include "UnderGrad.h"
//#include "Grad.h"
#include <string.h>
#include<cstdlib>
template <typename T>
class Queue
{
class Node
{
    friend class Queue;
    private:
    T* data;
    Node* next;
};
public:
    Queue() {head = NULL; tail = NULL; numNodes = 0;}
    ~Queue () {clear();}
    //overloaded operators
    T& operator [] (int);
    const T& operator [] (int) const;
    Queue<T>& operator += (T*);
    Queue<T>& operator += (Queue<T>&);
    friend Queue<T> operator+ (Queue<T> inList,T* tbAdded)
    {
        inList.pushBack(tbAdded);
        return inList;
    }
    //Queue<T> operator + (Queue<T>, Queue<T>&);
    //Queue<T>& operator -= (T*&);
    //Queue<T>& operator -= (const Queue<T>&);
    //Queue<T> operator - (T, const T&);
    //Queue<T> operator -(Queue<T>, const Queue<T>&);
    //Queue<T>& operator ! ();

    void pushBack(T*);
    //nice to be ble to clear all sometimes rather than write a for loop evertime you want ot clear the list
    void clear();
    void popFront();
    bool empty();
    T* front();
    int size() const;
    //used while an individual is using create app, so you can go back and edit prevous pages of the app
    T* getPrev(T*);
    T* back();
    void removeNode(T*);
    void sortList();
private:
Node* head;
Node* tail;
int numNodes;
};

//be carefule here with automatic variables
//as it will not create a new instance
template <typename T>
Queue<T>& Queue<T>::operator += (T* tbAdded)
{
    this -> pushBack(tbAdded);
return *this;
}

template <typename T>
Queue<T>& Queue<T>::operator += (Queue<T> &tbAdded)
{   
T* temp;
while (tbAdded.front() != NULL)
{
    temp = (T*) new T(*(tbAdded.front()));
    this -> pushBack(temp);
    tbAdded.popFront();
}
return *this;
}
template <typename T>
const T& Queue<T>::operator[] (int index) const
{
int count = 0;
Node *temp = head;
while (count < index && temp -> next != NULL)
{
    count++;
    temp = temp -> next;
}
if (count < index)
{
    std::cerr << "ArrayOutOfBounds: Index at: " << index << " ArrayLength: " << count << std::endl;
    exit(1);
}
else
{
    return *(temp -> data);
}
}
template <typename T>
T& Queue<T>::operator[] (int index)
{
int count = 0;
Node *temp = head;
while (count < index && temp -> next != NULL)
{
    count++;
    temp = temp -> next;
}
if (count < index)
{
    std::cerr << "ArrayOutOfBounds: Index at: " << index << " ArrayLength: " << count << std::endl;
    exit(1);
}
else
{
    return *(temp -> data);
}
}

//adds node to the back of the list
template <typename T>
void Queue<T>::pushBack(T *tbAdded)
{
    //  std::cout << "hello" << std::endl;
Node *temp = new Node;
//I copy the data into the heap, because for some operations i want to use save   local variables which poses problematic
temp -> data = tbAdded;
temp -> next  = NULL;
    //  std::cout << "hello" << std::endl;
if (head == NULL)
{
    //  std::cout << "bye" << std::endl;
    head = temp;
    tail = head;
}   
else
{
    //  std::cout << "shy" << std::endl;
    tail -> next = temp;
    tail = tail -> next;
}
    //  std::cout << "hello" << std::endl;
numNodes++;
}
//returns length of Queue
template <typename T>
int Queue<T>::size() const
{
return numNodes;
}

//removes a node formt he fornt of the list
template <typename T>
void Queue<T>::popFront()
{
if (head != NULL)
{
    Node *temp = head;
    head = head ->next;
    delete (temp -> data);
    delete (temp);
    numNodes--;
    if (numNodes > 0)
    {
        numNodes--;
        if (numNodes == 0)
        {
            tail = NULL;
        }
    }
}
}
//clears the list
template <typename T>
void Queue<T>::clear()
{
while (head != NULL)
{
    popFront();
}
}
//returns true iff list is empty
template <typename T>
bool Queue<T>::empty()
{
if (numNodes == 0)
{
    return true;
}
return false;
}

//returns data at fornt of list unless the list is empty then it returns null
template <typename T>
T* Queue<T>::front()
{
if (head != NULL)
{
    return head -> data;
}
else
{
    return NULL;
}
}
 //sorts undgrad info
//template <>
//inline void Queue<UnderGrad>::sortList()
//{
//  Node *temp = head;
//  UnderGrad *info;
//
//  for (int i = 0; i < size(); i++)
//  {
//      while (temp -> next)
//      {
//          std::string temp1 = (*(temp -> data)).getCourse();
//          std::string temp2 = (*(temp -> next -> data)).getCourse();
//          if (strcmp(temp1.c_str(), temp2.c_str()) > 0)
//          {
//              info = temp -> data;
//              temp -> data = temp -> next -> data;
//              temp -> next -> data = info;
//
//          }
//          else if (strcmp(temp1.c_str(), temp2.c_str()) == 0 && 
//              (*(temp -> data)).getGPA() < (*(temp -> next -> data)).getGPA())
//          {
//              info = temp -> data;
//              temp -> data = temp -> next -> data;
//              temp -> next -> data =    info;                 
//          }
//
//          temp = temp -> next;
//      }
//      
//      temp = head;
//  }
//  
//
//  
//}

//sorts Grad info
//template <>
//inline void Queue<Grad>::sortList()
//{
//  Node *temp = head;
//  Grad *info;
//
//  for (int i = 0; i < size(); i++)
//  {
//      while (temp -> next)
//      {
//          std::string temp1 = (*(temp -> data)).getCourse();
//          std::string temp2 = (*(temp -> next -> data)).getCourse();
//          std::string temp3 = (*(temp -> data)).getResearch();
//          std::string temp4 = (*(temp -> next -> data)).getResearch();
//          if (strcmp(temp1.c_str(), temp2.c_str()) > 0)
//          {
//              info = temp -> data;
//              temp -> data = temp -> next -> data;
//              temp -> next -> data = info;
//
//          }
//          else if (strcmp(temp1.c_str(), temp2.c_str()) == 0 && 
//              strcmp(temp3.c_str(), temp4.c_str()) > 0)
//          {
//              info = temp -> data;
//              temp -> data = temp -> next -> data;
//              temp -> next -> data = info;                    
//          }
//
//          temp = temp -> next;
//      }
//      temp = head;
//  }
//  
//
//  
//}

//these mothds i was considering using for a bonus but never completed they are used   no where in my code for now atleast
//this method is used when a back button is pressed so i can go from end to front of a list (since this is supposed to be a singly linked list this will be inneficient)
//that way if i have multiple things i.e related courses saved i can go back and edit  them b4 i save the app
template <typename T>
T* Queue<T>::getPrev(T* curNode)
{
if (curNode == head)
{
    return NULL;
}
Node *temp = head;
while (temp -> next != curNode)
{
    temp = temp -> next;
}
return temp -> data;
}

//if editing data i need a acces the last node in order to be able to go back and eit nodes back -> front
template <typename T>
T* Queue<T>::back()
{
if (tail != NULL)
{
    return head -> data;
}
else
{
    return NULL;
}
}
//if we decide to go back and edit we will need to remove the old node
template <typename T>
void Queue<T>::removeNode(T *tbRemoved)
{
Node *curNode, *prevNode;
curNode = head;
if (tbRemoved == head -> data)
{
    head = head -> next;
    delete curNode -> data;
    delete curNode;
}
while (curNode -> data != tbRemoved)
{
    prevNode = curNode;
    curNode = curNode -> next;
}
prevNode -> next = curNode -> next;
delete curNode -> data;
delete curNode;
}
#endif 

main.cpp

#include"Queue.h"
#include<iostream>
using namespace std;
int main()
{
Queue<int> intList;
Queue<int> intList1, intList2;
int *t;
intList.pushBack((int*) new int (5));
intList.pushBack((int*) new int (10));
intList.pushBack((int*) new int (15));
intList.pushBack((int*) new int (20));

intList += ((int*) new int (25));
cout << intList[4] << "!" << endl;
cout << "?" << endl;
cout << "?" << endl;
cout << "?" << endl;
intList = intList + ((int*) new int (35));
cout << intList[5] << "!" << endl;
intList += ((int*) new int (30));
cout << intList[5] << "!" << endl;
cout << "?" << endl;
cout << "?" << endl;
cout << "?" << endl;
intList1.pushBack((int*) new int (2));
intList1.pushBack((int*) new int (7));
intList1.pushBack((int*) new int (9));
intList1.pushBack((int*) new int (11));
intList += intList1;
    intList1.clear();
cout << intList[6] << "!" << endl;
cout << intList[2] << "!" << endl;
intList.clear();
intList1.clear();
cout << "?" << endl;

Queue<string> strList;
cout << "?" << endl;    
strList.pushBack((string*) new string("hi"));
strList.pushBack((string*) new string("bi"));
strList.pushBack((string*) new string("di"));
strList.pushBack((string*) new string("ki"));
cout << "?" << endl;
cout << strList[2] << "!" << endl;
return 0;
}

输出:25!

分段故障(堆芯转储(

我需要实现+运算符,这样它就会接收一个数据指针,并返回一个由旧列表和新节点组成的新列表。我在类模板中编写了这个函数,因为我读到在外部编写它是一个问题,就像我的其他函数一样。我试了几种方法让发挥作用

  • 使用我定义的+=赋值运算符(plus equals可以很好地工作,但当我将其与他的函数一起使用时,会出现问题吗?(

  • 我试着创建一个新列表,并用新旧数据填充它,然后返回该列表,但没有成功。。所以现在我很困惑,一个指向正确方向的点会很可怕!


编辑:我已经尝试从类定义中删除我的+运算符,并将其简化为接受一个参数

template <typename T>
Queue<T>& Queue<T>::operator+ (T* tbAdded)
{
Queue<T> *temp = (Queue<T> *) new Queue<T>(*this);
temp -> pushBack(tbAdded);
  //    std::cout << (*temp)[5] << std::endl;
  //    std::cout << (*this)[3] << std::endl;
return *temp;
}

在我对它的所有测试中,这似乎是"有效的",但在我的测试结束时(在所有输出正确后(,出现了一个分段故障

您需要为类定义一个复制构造函数和一个赋值运算符。这些将需要逐个元素复制整个列表。

在以下代码中:

Queue<T> *temp = (Queue<T> *) new Queue<T>(*this);

CCD_ 1调用复制构造函数。由于您没有提供一个,编译器会为您生成一个。自动生成的复制构造函数只需对对象进行逐字段的复制。换句话说,它复制headtail指针,以及numNodes的值。

然而,这是错误的,因为当相同的元素超出范围时,原始元素和副本都会试图解除分配。这导致了未定义的行为,并解释了您所看到的崩溃。

请参阅"三条规则"。