实验目的
1. 理解面向对象思想中泛型的概念、重要意义;
2. 正确声明和使用模板类;
实验内容
- 仿照std::vector, 以模板类的形式实现一个通用的顺序存储容器 MyVector。
- 仿照std:: list, 以模板类的形式实现一个通用的链式存储容器MyList。
- 以模板类的形式实现栈和队列。
基本要求:
1)体现泛型思想、体现继承和派生;
2)要给出关于设计思想的描述或是对设计过程做出必要说明和解释。
3)编写相应的测试用例来验证或者测试所设计类的基本功能及效率。
实验过程
MyVictor.h:
//
// Created by HASEE on 2022/6/6.
//
#ifndef UNTITLED_MYVECTOR_H
#define UNTITLED_MYVECTOR_H
#include <iostream>
using namespace std;
template<typename T>
class MyVector {
template<typename U>
friend ostream& operator<< (ostream &out, const MyVector<U> &obj);
private:
int len=0;
T *space= nullptr;
public:
int getlen(){
return len;
}
explicit MyVector(int size=0);
~MyVector();//析构
MyVector(const MyVector& myv1); //拷贝构造
MyVector(MyVector &&myv) noexcept ; //移动构造
//重载[] =
T& operator[](int index);
MyVector& operator=(const MyVector& mv2);
};
#endif //UNTITLED_MYVECTOR_H
MyVictor.cpp:
//
// Created by HASEE on 2022/6/6.
//
#include "MyVector.h"
#include <iostream>
using namespace std;
template<typename T>
MyVector<T>::MyVector(int size) {
len=size;
space=new T[len];
}
template<typename T>
MyVector<T>::~MyVector() { //析构函数
if(space != nullptr){
delete[] space;
space= nullptr;
len=0;
}
}
template<typename T>
MyVector<T>::MyVector(const MyVector &myv1) { //拷贝构造函数
len=myv1.len;
space=new T[len];
for(int i=0;i<len;++i){
space[i]=myv1.space[i]; //复制内容
}
}
//[]重载
template<typename T>
T &MyVector<T>::operator[](int index) {
return space[index];
}
//移动构造
template<typename T>
MyVector<T>::MyVector(MyVector &&myv) noexcept {
if(myv.space == nullptr)
return;
space=myv.space;
myv.space= nullptr;
}
template<typename T>
MyVector<T> & MyVector<T>::operator=(const MyVector<T> &mv2) {
if(space!= nullptr){
delete[] space;
space= nullptr;
len=0;
}
len=mv2.len;
space=new T[len];
for (int i = 0; i < len; ++i) {
space[i]=mv2.space[i];
}
return *this;
}
//<<重载
template<typename T>
ostream & operator << (ostream &out, const MyVector<T> &s) {
for(int i=0;i<s.len;++i){
out<<s.space[i];
}
out<<endl;
return out;
}
int main(){
MyVector<int> mv1(10);
for (int i = 0; i < mv1.getlen(); i++){
mv1[i] = i + 1;//调用重载函数[]
cout << mv1[i]<<" ";
}
cout << endl;
MyVector<int> mv2 = mv1;//调用拷贝构造函数
for (int i = 0; i < mv2.getlen(); ++i){
cout<<mv2[i]<<" ";
}
cout << mv2 <<endl; //调用重载<<
// system("pause");
}
结果:
LinarList.h(线性表基类):
//
// Created by HASEE on 2022/6/7.
//
#ifndef UNTITLED_LINARLIST_H
#define UNTITLED_LINARLIST_H
template <typename T>
class LinearList{
public:
LinearList(){}
virtual ~LinearList(){}
//纯虚函数
virtual int Length()const = 0;//求表的长度
// virtual int Search(T& x)const = 0;
// virtual int Locate(int i)const = 0;//在表中定位第i个元素位置,返回表项序号
virtual T getData(int i)const = 0; //取第i个的值
// virtual void setData(int i, T& x) = 0;//修改第 i个的值
virtual bool Insert(int i, T& x) = 0;
virtual T Remove(int i) = 0;
virtual bool IsEmpty()const = 0;//判空
};
#endif //UNTITLED_LINARLIST_H
MyList.h (单链表):
//
// Created by HASEE on 2022/6/6.
//
#ifndef UNTITLED_MYLIST_H
#define UNTITLED_MYLIST_H
#include "LinarList.h"
template <typename T>
struct Node{
T data;//数据域
Node<T>* link;//指针域,指向下一个节点
Node() //仅初始化指针的构造函数
{
Node<T> *ptr = NULL;
link = ptr;
}
Node(const T& item, Node<T> *ptr = NULL) //初始化数据和指针成员的构造函数
{
data = item;
link = ptr;
}
};
template <typename T>
class MyList : public LinearList<T>{
protected:
Node<T>* first; //头节点,使第i个结点对应下标第i个元素
public:
MyList(){
first=new Node<T>;}
MyList(const T& x){//指定头节点
first=new Node<T>(x);
}
MyList(MyList<T>& l);
~MyList(){
makeEmpty();
}
void makeEmpty(){
Node<T>* q;
while (first->link != NULL)//找到各个结点并删除
{
q = first->link; //保存被删结点
first->link = q->link; //从链上摘下该结点,通过头指针的link的移动来实现
delete q; //删除
}
}
Node<T>* getHead()const{
return first;}
void setHead(Node<T>* p){
first=p;
}
int Length()const;
// int Search(T& x)const;
Node<T>* Locate(int i)const;
T getData(int i)const;
// void setData(int i, T& x);
bool insert(T& x);//尾插入
bool Insert(int i, T& x);
T Remove(int i);
// void headAdd();
// void tailAdd();
bool IsEmpty()const{
return first->link == NULL;
}
// void input();
// void output();
MyList<T>& operator=(const MyList<T>& L);
};
#endif //UNTITLED_MYLIST_H
Mylist.cpp(基于单链表类实现栈和队列):
//
// Created by HASEE on 2022/6/6.
//
#include <iostream>
#include "MyList.h"
#include <cstdio>
template<typename T>
MyList<T>::MyList(MyList<T> &l) {
T value;
Node<T>* fptr=l.getHead();//声明一个结点遍历参数链表
Node<T>* nptr=first=new Node<T>;//新链表的头结点
while (fptr->link != NULL){//逐个复制参数链表的结点
value=fptr->link->data;
nptr->link=new Node<T>(value);
nptr=nptr->link;
fptr=fptr->link;
}
}
//O(n)
template<typename T>
int MyList<T>::Length() const {
Node<T>* p=first->link; //指向一号节点
int count=0;
while (p!= NULL){
p=p->link;
count++;
}
return count;
}
//O(n)
template<typename T>
Node<T> *MyList<T>::Locate(int i) const {//定位第i个元素的位置
if (i < 0) return NULL; // i不合理
Node<T>* current = first;
int k = 0;
while (current != NULL && k < i)
{
current = current->link;
k++;
}
return current; //返回第 i 号结点地址或NULL
}
template<typename T>
T MyList<T>::getData(int i) const {
if(i<1)
return NULL;
Node<T>* current= Locate(i);
return current->data;
}
//template<typename T>
//void MyList<T>::setData(int i, T &x) {//修改第i个元素的值
// if(i<1)
// return;
// Node<T>* current= Locate(i);
// if(current== nullptr)
// return;
// current->data=x;
//}
//O(n)
template<typename T>
bool MyList<T>::Insert(int i, T &x) {
Node<T>* current= Locate(i);
if(current== NULL)//无插入位置
return false;
Node<T>* newNode=new Node<T>(x);
// 创建新节点
if(newNode== NULL)
return false;
newNode->link=current->link;
current->link=newNode;
return true;
}
//O(n)
template<typename T>
T MyList<T>::Remove(int i) {//删除第i个元素,x带回删除值
T x;
Node<T>* current= Locate(i-1);
if(current== NULL||current->link== NULL)
return false;//删除不成功
Node<T>* del=current->link;
current->link=del->link;
x=del->data;
delete del;
return x;
}
template<typename T>
MyList<T> &MyList<T>::operator=(const MyList<T> &L) {
T value;
Node<T>* srcptr=L.getHead();
Node<T>* tptr=first;
makeEmpty();//清空后复制
while (srcptr->link!= nullptr){
value=srcptr->link->data;
tptr->link=new Node<T>(value);
tptr=tptr->link;
srcptr= srcptr->link;
}
tptr->link= nullptr;
return *this;
}
template<typename T>
bool MyList<T>::insert(T& x) {
if(this->IsEmpty()){
Node<T>* newNode=new Node<T>(x);
first->link=newNode;
return true;
}
Insert(Length(),x);
return true;
}
//栈
template<typename T>
class LinkedStack: public MyList<T>{
public:
void push(T x){
Node<T>* tmp=new Node<T>;
tmp->data=x;
this->insert(x);
}
T pop(){//返回出栈值
int len=this->Length();
T x=this->Remove(len);
return x;
}
};
//队列
template<typename T>
class LinkedQueue:public MyList<T>{
public:
void EnQueue(T x){
Node<T>* tmp=new Node<T>;
tmp->data=x;
this->insert(x);
}
T DeQueue(){//返回出队值
T x= this->Remove(1);
return x;
};
};
//测试
int main(){
LinkedStack<int> stack;
int a=11;
stack.insert(a);
stack.push(1);
stack.push(2);
stack.push(3);
int i=stack.pop();
int m=stack.getData(2);
std::cout<<m<<std::endl;
std::cout<<i<<std::endl;
LinkedQueue<int> queue;
// int b=22;
// queue.insert(b);
queue.EnQueue(12);
queue.EnQueue(11);
queue.EnQueue(20);
int out=queue.DeQueue();
std::cout<<out<<std::endl;
}
结果:
实验总结
在对<<进行重载时,常常不能编译,虽然写了重载但是貌似编译器找不到然后就一直报这个错误,网上也找了很多资料不知道是什么原因,后面突然找到了一个解决办法,在友元函数前再新建一个模板,然后就可以编译了,但是仍然不清楚这是什么原因。
在使用继承时,如果构造类为模板类的话,派生类不能直接使用继承到的数据和方法,直接写的话会出现找不到标识的错,想要解决这个问题需要通过this指针使用。