【c++思维导图与代码示例】08 模板与群体函数

【c++思维导图与代码示例】08 模板与群体函数

思维导图:

在这里插入图片描述

代码示例:

  • 示例1:
/*************************************************
**
**Description: 函数模板示例,学会函数模板的定义与使用
**
** Author:慕灵阁-wupke
** Time:2021-12-20
** Versions :8-1.cpp
** 
*
***************************************************/

// #include <iostream>
// using namespace std;

// 1、 使用函数模板,求不同数据类型的绝对值
// template<typename T>    //语法形式
// T abs(T x){
//     return x<0? -x : x ;     //求绝对值, x < 0 则返回 - x ,否则返回 x
// }

// int main(){
//     int n=-5;
//     double b = -5.55;
//     cout << abs(n) << endl;
//     cout << abs(b) << endl;

//     system("pause");
//     return 0;
// }



#include <iostream>
using namespace std;

//2、使用函数模板显示任何类型一维数组元素

template<class T>  //定义函数模板
void outputArray(const T *array, int count) {
    for (int i=0;i < count;i++)
        cout << array[i] << "  ";  //如果数组元素是类的对象,需要该对象所属类重载了流插入运算符 “ << ”
    cout<<endl; 
}

int main(){
    const int A_COUNT = 8,B_COUNT = 8,C_COUNT = 20;   // 三种不同类型的数组
    int a[A_COUNT] = {1,2,3,4,5,6,7,8};
    double b[B_COUNT] = {1.1,2.2,3.3,4.4,5.5,6.6,7.7,8.8};
    char  c[C_COUNT] = " Welcome! ";

    cout << " a array contains: " << endl;
    outputArray(a,A_COUNT);                      // 调用函数模板(编译器根据不同的类型,去置换 T 的适用类型函数,编译器重载了3 种不同类型的函数)
    cout << " b array contains: " << endl;
    outputArray(b,B_COUNT);                      // 调用函数模板
    cout << " c array contains: " << endl;
    outputArray(c,C_COUNT);                      // 调用函数模板
    
    
    //system("pause");

    return 0;

}


  • 示例2:
/*************************************************
**
**Description:  类模板示例:实现对任意类型数据进行存取(类模板store 容纳一个数据项),了解类模板的声明与使用
类模板的作用:
使用类模板使用户可以为类声明一种模式,使得类中的某些数据成员、某些成员函数的参数、
某些成员函数的返回值,能取任意类型(包括基本类型的和用户自定义类型)。


类模板的声明:
• 类模板 template <模板参数表> class 类名 {类成员声明};
• 如果需要在类模板以外定义其成员函数,则要采用以下的形式:

 template <模板参数表> 
 类型名 类名<模板参数标识符列表>::函数名(参数表)
**
** Author:慕灵阁-wupke
** Time:2021-12-20
** Versions :8-2.cpp
** 
*
***************************************************/

#include <iostream>
#include<cstdlib>

using namespace std;
struct Student {	// 结构体Student
	int id;		//学号
	float gpa;	//平均分
};  

template <class T>  //类模板:实现对任意类型数据进行存取(类模板store 容纳一个数据项)
class Store {
private:
	T item;			// item用于存放任意类型的数据
	bool haveValue;	// haveValue标记item是否已被存入内容
public:
	Store();		// 缺省形式(无形参)的构造函数
	T &getElem();	//提取数据函数
	void putElem(const T &x);  //存入数据函数
};

//以下实现各成员函数。
template <class T>	//缺省构造函数的实现 
Store<T>::Store(): haveValue(false) { }

template <class T>                //提取数据函数的实现
T &Store<T>::getElem() {
	if (!haveValue) {	//如果试图提取未初始化的数据,则终止程序
		cout << "No item present!" << endl;
		exit(1);	//使程序完全退出,返回到操作系统。
		//参数可用来表示程序终止的原因,可以被操作系统接收
	}
	return item;    // 返回item中存放的数据 
}

template <class T>	//存入数据函数的实现 
void Store<T>::putElem(const T &x) {
	haveValue = true;	// 将haveValue 置为true,表示item中已存入数值
	item = x;			// 将x值存入item
}

int main() {
	Store<int> s1, s2;	//定义两个Store<int>类对象,其中数据成员item为int类型
	s1.putElem(3);	//向对象S1中存入数据(初始化对象S1)
	s2.putElem(-7);	//向对象S2中存入数据(初始化对象S2)
	cout << s1.getElem() << "  " << s2.getElem() << endl;	//输出对象S1和S2的数据成员

	Student g = { 1000, 23 };	//定义Student类型结构体变量的同时赋以初值
	Store<Student> s3;	//定义Store<Student>类对象s3,其中数据成员item为Student类型
	s3.putElem(g); //向对象D中存入数据(初始化对象D)
	cout << "The student id is " << s3.getElem().id << endl;	//输出对象s3的数据成员


    // 放开以下代码,程序出错,运行即停止

	// Store<double> d;	//定义Store<double>类对象s4,其中数据成员item为double类型
	// cout << "Retrieving object d... ";
	// cout << d.getElem() << endl;  //输出对象D的数据成员
	// //由于d未经初始化,在执行函数D.getElement()过程中导致程序终止


    system("pause");

	return 0;
}

  • 示例3:
/*************************************************
**
**Description:  动态数组类模板示例:
如何封装一个动态数组类?
定义一个希望可以容纳任何元素类型的数组(这里数组元素类型设置为类型参数)

定义的Array对象,(数组类模板),如果不重载指针运算符,函数调用不能实现,
(主调函数的实参是一个对象,而形参是一个int 指针;类型不相符)
(重载指针运算符,将a转化为指针类型)
**
** Author:慕灵阁-wupke
** Time:2021-12-20
** Versions :8-3.cpp
** 
*
***************************************************/

// 例9-3 动态数组类模板程序  (ARRAY.h)
//Array.h
// #ifndef ARRAY_H
// #define ARRAY_H
#include <cassert> //(单独做头文件的引用)

#include <iostream> // (单独做主函数文件的引用)
using namespace std;



//数组类模板定义
template <class T> 
class Array {
private:
	T* list;	//T类型指针,用于存放动态分配的数组内存首地址
	int size;	//数组大小(元素个数)
public:
	Array(int sz = 50);			//构造函数
	Array(const Array<T> &a);	//拷贝构造函数
	~Array();	//析构函数
	Array<T> & operator = (const Array<T> &rhs); //重载"="使数组对象可以整体赋值
	T & operator [] (int i);	//重载"[]",使Array对象可以起到C++普通数组的作用
	const T & operator [] (int i) const;	//"[]"运算符的const版本
	operator T * ();	//重载到T*类型的转换,使Array对象可以起到C++普通数组的作用
	operator const T * () const;	//到T*类型转换操作符的const版本
	int getSize() const;	//取数组的大小
	void resize(int sz);	//修改数组的大小
};

//构造函数
template <class T>
Array<T>::Array(int sz) {
	assert(sz >= 0);	//sz为数组大小(元素个数),应当非负
	size = sz;	// 将元素个数赋值给变量size
	list = new T [size];	//动态分配size个T类型的元素空间
}

//析构函数
template <class T>
Array<T>::~Array() {
	delete [] list;
}

//拷贝构造函数
template <class T>
Array<T>::Array(const Array<T> &a) {
	//从对象x取得数组大小,并赋值给当前对象的成员
	size = a.size;
	//为对象申请内存并进行出错检查
	list = new T[size];	// 动态分配n个T类型的元素空间
	//从对象X复制数组元素到本对象  
	for (int i = 0; i < size; i++)
		list[i] = a.list[i];
}

//重载"="运算符,将对象rhs赋值给本对象。实现对象之间的整体赋值
template <class T>
Array<T> &Array<T>::operator = (const Array<T>& rhs) {
	if (&rhs != this) {
		//如果本对象中数组大小与rhs不同,则删除数组原有内存,然后重新分配
		if (size != rhs.size) {
			delete [] list;		//删除数组原有内存
			size = rhs.size;	//设置本对象的数组大小
			list = new T[size];	//重新分配n个元素的内存
		}
		//从对象X复制数组元素到本对象  
		for (int i = 0; i < size; i++)
			list[i] = rhs.list[i];
	}
	return *this;	//返回当前对象的引用
}

//重载下标运算符,实现与普通数组一样通过下标访问元素,并且具有越界检查功能
template <class T>
T &Array<T>::operator[] (int n) {
	assert(n >= 0 && n < size);	//检查下标是否越界
	return list[n];			//返回下标为n的数组元素
}

template <class T>
const T &Array<T>::operator[] (int n) const {
	assert(n >= 0 && n < size);	//检查下标是否越界
	return list[n];			//返回下标为n的数组元素
}

//重载指针转换运算符,将Array类的对象名转换为T类型的指针,
//指向当前对象中的私有数组。
//因而可以象使用普通数组首地址一样使用Array类的对象名
template <class T>
Array<T>::operator T * () {
	return list;	//返回当前对象中私有数组的首地址
}

template <class T>
Array<T>::operator const T * () const {
	return list;	//返回当前对象中私有数组的首地址
}

//取当前数组的大小
template <class T>
int Array<T>::getSize() const {
	return size;
}

// 将数组大小修改为sz
template <class T>
void Array<T>::resize(int sz) {
	assert(sz >= 0);	//检查sz是否非负
	if (sz == size)	//如果指定的大小与原有大小一样,什么也不做
		return;
	T* newList = new T [sz];	//申请新的数组内存
	int n = (sz < size) ? sz : size;	//将sz与size中较小的一个赋值给n
	//将原有数组中前n个元素复制到新数组中
	for (int i = 0; i < n; i++)
		newList[i] = list[i];
	delete[] list;		//删除原数组
	list = newList;	// 使list指向新数组
	size = sz;	//更新size
}
// #endif  //ARRAY_H


// 主函数

void read(int *p, int n) {
 for (int i = 0; i < n; i++)
   cin >> p[i];
}
int main() {
Array<int> a(15);
read(a, 5);

for (int i = 0; i<10;i++){
	cout << "read[" << i <<"] = "<< read[i] <<" "<<endl;
}

system("pause");
return 0;
}


/*主函数对比,如果不重载指针运算符,函数调用不能实现,(主调函数的实参是一个对象,而形参是一个int 指针;类型不相符)
(重载指针运算符,将a转化为指针类型)/ /*/ 

// 指针转换运算符的作用
// #include <iostream>
// using namespace std;
// void read(int *p, int n) {
//  for (int i = 0; i < n; i++)
//     cin >> p[i];
// }
// int main() {
//  int a[10];
//  read(a, 10);
//  return 0;
// }


  • 示例4:
/*************************************************
**
**Description: Array 类的应用示例:求范围2~N中的质数,N在程序运行时由键盘输入。

**
** Author:慕灵阁-wupke
** Time:2021-12-20
** Versions :8-4.cpp
** 
*
***************************************************/


//主函数
#include <iostream>
#include <iomanip>
#include "Arrary.h"
using namespace std;

int main() {
	Array<int> a(10);	// 用来存放质数的数组,初始状态有10个元素。
	int count = 0;

	int n;
	cout << "Enter a value >= 2 as upper limit for prime numbers: ";
	cin >> n;

	for (int i = 2; i <= n; i++) {
		//检查i是否能被比它小的质数整除
		bool isPrime = true;
		for (int j = 0; j < count; j++)
			if (i % a[j] == 0) {	//若i被a[j]整除,说明i不是质数
				isPrime = false;
				break;
			}

		//把i写入质数表中
		if (isPrime) {
			//如果质数表满了,将其空间加倍
			if (count == a.getSize())
				a.resize(count * 2);
			a[count++] = i;
		}
	}

	for (int i = 0; i < count; i++)	//输出质数
		cout << setw(8) << a[i];
	cout << endl;

    system("pause");
	return 0;
}






//Array.h 头文件
#ifndef ARRAY_H
#define ARRAY_H

#include <cassert>

//数组类模板定义
template <class T> 
class Array {
private:
	T* list;	//T类型指针,用于存放动态分配的数组内存首地址
	int size;	//数组大小(元素个数)
public:
	Array(int sz = 50);			//构造函数
	Array(const Array<T> &a);	//拷贝构造函数
	~Array();	//析构函数
	Array<T> & operator = (const Array<T> &rhs); //重载"="使数组对象可以整体赋值
	T & operator [] (int i);	//重载"[]",使Array对象可以起到C++普通数组的作用
	const T & operator [] (int i) const;	//"[]"运算符的const版本
	operator T * ();	//重载到T*类型的转换,使Array对象可以起到C++普通数组的作用
	operator const T * () const;	//到T*类型转换操作符的const版本
	int getSize() const;	//取数组的大小
	void resize(int sz);	//修改数组的大小
};

//构造函数
template <class T>
Array<T>::Array(int sz) {
	assert(sz >= 0);	//sz为数组大小(元素个数),应当非负
	size = sz;	// 将元素个数赋值给变量size
	list = new T [size];	//动态分配size个T类型的元素空间
}

//析构函数
template <class T>
Array<T>::~Array() {
	delete [] list;
}

//拷贝构造函数
template <class T>
Array<T>::Array(const Array<T> &a) {
	//从对象x取得数组大小,并赋值给当前对象的成员
	size = a.size;
	//为对象申请内存并进行出错检查
	list = new T[size];	// 动态分配n个T类型的元素空间
	//从对象X复制数组元素到本对象  
	for (int i = 0; i < size; i++)
		list[i] = a.list[i];
}

//重载"="运算符,将对象rhs赋值给本对象。实现对象之间的整体赋值
template <class T>
Array<T> &Array<T>::operator = (const Array<T>& rhs) {
	if (&rhs != this) {
		//如果本对象中数组大小与rhs不同,则删除数组原有内存,然后重新分配
		if (size != rhs.size) {
			delete [] list;		//删除数组原有内存
			size = rhs.size;	//设置本对象的数组大小
			list = new T[size];	//重新分配n个元素的内存
		}
		//从对象X复制数组元素到本对象  
		for (int i = 0; i < size; i++)
			list[i] = rhs.list[i];
	}
	return *this;	//返回当前对象的引用
}

//重载下标运算符,实现与普通数组一样通过下标访问元素,并且具有越界检查功能
template <class T>
T &Array<T>::operator[] (int n) {
	assert(n >= 0 && n < size);	//检查下标是否越界
	return list[n];			//返回下标为n的数组元素
}

template <class T>
const T &Array<T>::operator[] (int n) const {
	assert(n >= 0 && n < size);	//检查下标是否越界
	return list[n];			//返回下标为n的数组元素
}

//重载指针转换运算符,将Array类的对象名转换为T类型的指针,
//指向当前对象中的私有数组。
//因而可以象使用普通数组首地址一样使用Array类的对象名
template <class T>
Array<T>::operator T * () {
	return list;	//返回当前对象中私有数组的首地址
}

template <class T>
Array<T>::operator const T * () const {
	return list;	//返回当前对象中私有数组的首地址
}

//取当前数组的大小
template <class T>
int Array<T>::getSize() const {
	return size;
}

// 将数组大小修改为sz
template <class T>
void Array<T>::resize(int sz) {
	assert(sz >= 0);	//检查sz是否非负
	if (sz == size)	//如果指定的大小与原有大小一样,什么也不做
		return;
	T* newList = new T [sz];	//申请新的数组内存
	int n = (sz < size) ? sz : size;	//将sz与size中较小的一个赋值给n
	//将原有数组中前n个元素复制到新数组中
	for (int i = 0; i < n; i++)
		newList[i] = list[i];
	delete[] list;		//删除原数组
	list = newList;	// 使list指向新数组
	size = sz;	//更新size
}
#endif  //ARRAY_H


  • 示例5:

/*************************************************
**
**Description: //LinkedList.h 链表类模板
  生成链表、插入结点、查找结点、删除结点、遍历链表、清空链表 的声明构建
**
** Author:慕灵阁-wupke
** Time:2021-12-20
** Versions :8-4.cpp
** 
*
***************************************************/

//Node.h
#ifndef NODE_H
#define NODE_H

//类模板的定义
template <class T>
class Node {
private:
	Node<T> *next;	//指向后继结点的指针
public:
	T data;	//数据域

	Node (const T &data, Node<T> *next = 0);    //构造函数
	void insertAfter(Node<T> *p);	//在本结点之后插入一个同类结点p 
	Node<T> *deleteAfter();	//删除本结点的后继结点,并返回其地址
	Node<T> *nextNode();				 //获取后继结点的地址
	const Node<T> *nextNode() const;	 //获取后继结点的地址
};

//类的实现部分
//构造函数,初始化数据和指针成员
template <class T>
Node<T>::Node(const T& data, Node<T> *next/* = 0 */) : data(data), next(next) { }
  
//返回后继结点的指针
template <class T>
Node<T> *Node<T>::nextNode() {
	return next;
}

//返回后继结点的指针
template <class T>
const Node<T> *Node<T>::nextNode() const {
	return next;
} 

//在当前结点之后插入一个结点p 
template <class T>
void Node<T>::insertAfter(Node<T> *p) {
    p->next = next;	//p结点指针域指向当前结点的后继结点
    next = p;		//当前结点的指针域指向p 
}

//删除当前结点的后继结点,并返回其地址
template <class T>
Node<T> *Node<T>::deleteAfter() {
	Node<T> *tempPtr = next;	//将欲删除的结点地址存储到tempPtr中
	if (next == 0)	//如果当前结点没有后继结点,则返回空指针
		return 0;
	next = tempPtr->next;	//使当前结点的指针域指向tempPtr的后继结点
	return tempPtr;			//返回被删除的结点的地址
}

#endif //NODE_H









#ifndef LINKEDLIST_H
#define LINKEDLIST_H
#include "Node.h"

template <class T>
class LinkedList {
private:
    //数据成员:
    Node<T> *front, *rear;  //表头和表尾指针
    Node<T> *prevPtr, *currPtr;   //记录表当前遍历位置的指针,由插入和删除操作更新
    int size;   //表中的元素个数
    int position;   //当前元素在表中的位置序号。由函数reset使用

    //函数成员:
    //生成新结点,数据域为item,指针域为ptrNext
    Node<T> *newNode(const T &item,Node<T> *ptrNext=NULL);

    //释放结点
    void freeNode(Node<T> *p);

    //将链表L 拷贝到当前表(假设当前表为空)。
    //被拷贝构造函数、operator = 调用
    void copy(const LinkedList<T>& L);

public:
    LinkedList();   //构造函数
    LinkedList(const LinkedList<T> &L);  //拷贝构造函数
    ~LinkedList();  //析构函数
    LinkedList<T> & operator = (const LinkedList<T> &L); //重载赋值运算符

    int getSize() const;    //返回链表中元素个数
    bool isEmpty() const;   //链表是否为空

    void reset(int pos = 0);//初始化游标的位置
    void next();    //使游标移动到下一个结点
    bool endOfList() const; //游标是否到了链尾
    int currentPosition() const;    //返回游标当前的位置

    void insertFront(const T &item);    //在表头插入结点
    void insertRear(const T &item);     //在表尾添加结点
    void insertAt(const T &item);       //在当前结点之前插入结点
    void insertAfter(const T &item);    //在当前结点之后插入结点

    T deleteFront();    //删除头结点
    void deleteCurrent();   //删除当前结点

    T& data();              //返回对当前结点成员数据的引用
    const T& data() const;   //返回对当前结点成员数据的常引用

    //清空链表:释放所有结点的内存空间。被析构函数、operator= 调用
    void clear();
};

template <class T> //生成新结点
Node<T> *LinkedList<T>::newNode(const T& item, Node<T>* ptrNext)
{
    Node<T> *p;
    p = new Node<T>(item, ptrNext);
    if (p == NULL)
    {
        cout << "Memory allocation failure!\n";
        exit(1);
    }
    return p;
}

template <class T>
void LinkedList<T>::freeNode(Node<T> *p) //释放结点
{
    delete p;
}

template <class T>
void LinkedList<T>::copy(const LinkedList<T>& L) //链表复制函数
{
    Node<T> *p = L.front;   //P用来遍历L 
    int pos;
    while (p != NULL)   //将L中的每一个元素插入到当前链表最后
    {
        insertRear(p->data);
        p = p->nextNode();
    }
    if (position == -1) //如果链表空,返回
        return;
    //在新链表中重新设置prevPtr和currPtr
    prevPtr = NULL;
    currPtr = front;
    for (pos = 0; pos != position; pos++)
    {
        prevPtr = currPtr;
        currPtr = currPtr->nextNode();
    }
}

template <class T>  //构造一个新链表,将有关指针设置为空,size为0,position为-1
LinkedList<T>::LinkedList() : front(NULL), rear(NULL),
prevPtr(NULL), currPtr(NULL), size(0), position(-1)
{}

template <class T>
LinkedList<T>::LinkedList(const LinkedList<T>& L)  //拷贝构造函数
{
    front = rear = NULL;
    prevPtr = currPtr = NULL;
    size = 0;
    position = -1;
    copy(L);
}

template <class T>
LinkedList<T>::~LinkedList()    //析构函数
{
    clear();
}

template <class T>
LinkedList<T>& LinkedList<T>::operator=(const LinkedList<T>& L)//重载"="
{
    if (this == &L) // 不能将链表赋值给它自身
        return *this;
    clear();
    copy(L);
    return *this;
}

template <class T>
int LinkedList<T>::getSize() const  //返回链表大小的函数
{
    return size;
}

template <class T>
bool LinkedList<T>::isEmpty() const //判断链表为空否
{
    return size == 0;
}

template <class T>
void LinkedList<T>::reset(int pos)  //将链表当前位置设置为pos 
{
    int startPos;
    if (front == NULL)  // 如果链表为空,返回
        return;
    if (pos < 0 || pos > size - 1)  // 如果指定位置不合法,中止程序
    {
        std::cerr << "Reset: Invalid list position: " << pos << endl;
        return;
    }
    // 设置与遍历链表有关的成员
    if (pos == 0)   // 如果pos为0,将指针重新设置到表头
    {
        prevPtr = NULL;
        currPtr = front;
        position = 0;
    }
    else    // 重新设置 currPtr, prevPtr, 和 position 
    {
        currPtr = front->nextNode();
        prevPtr = front;
        startPos = 1;
        for (position = startPos; position != pos; position++)
        {
            prevPtr = currPtr;
            currPtr = currPtr->nextNode();
        }
    }
}

template <class T>
void LinkedList<T>::next()  //将prevPtr和currPtr向前移动一个结点
{
    if (currPtr != NULL)
    {
        prevPtr = currPtr;
        currPtr = currPtr->nextNode();
        position++;
    }
}

template <class T>
bool LinkedList<T>::endOfList() const   // 判断是否已达表尾
{
    return currPtr == NULL;
}

template <class T>
int LinkedList<T>::currentPosition() const  // 返回当前结点的位置
{
    return position;
}

template <class T>
void LinkedList<T>::insertFront(const T& item)   // 将item插入在表头
{
    if (front != NULL)  // 如果链表不空则调用Reset 
        reset();
    insertAt(item); // 在表头插入
}

template <class T>
void LinkedList<T>::insertRear(const T& item)   // 在表尾插入结点
{
    Node<T> *nNode;
    prevPtr = rear;
    nNode = newNode(item);  // 创建新结点
    if (rear == NULL)   // 如果表空则插入在表头
        front = rear = nNode;
    else
    {
        rear->insertAfter(nNode);
        rear = nNode;
    }
    currPtr = rear;
    position = size;
    size++;
}

template <class T>
void LinkedList<T>::insertAt(const T& item) // 将item插入在链表当前位置
{
    Node<T> *nNode;
    if (prevPtr == NULL)    // 插入在链表头,包括将结点插入到空表中
    {
        nNode = newNode(item, front);
        front = nNode;
    }
    else    // 插入到链表之中. 将结点置于prevPtr之后
    {
        nNode = newNode(item);
        prevPtr->insertAfter(nNode);
    }
    if (prevPtr == rear)    //正在向空表中插入,或者是插入到非空表的表尾
    {
        rear = nNode;   //更新rear 
        position = size;    //更新position 
    }
    currPtr = nNode;    //更新currPtr
    size++; //使size增值
}

template <class T>
void LinkedList<T>::insertAfter(const T& item)  // 将item 插入到链表当前位置之后
{
    Node<T> *p;
    p = newNode(item);
    if (front == NULL)   // 向空表中插入
    {
        front = currPtr = rear = p;
        position = 0;
    }
    else    // 插入到最后一个结点之后
    {
        if (currPtr == NULL)
            currPtr = prevPtr;
        currPtr->insertAfter(p);
        if (currPtr == rear)
        {
            rear = p;
            position = size;
        }
        else
            position++;
        prevPtr = currPtr;
        currPtr = p;
    }
    size++;              // 使链表长度增值
}

template <class T>
T LinkedList<T>::deleteFront()  // 删除表头结点
{
    T item;
    reset();
    if (front == NULL)
    {
        cerr << "Invalid deletion!" << endl;
        exit(1);
    }
    item = currPtr->data;
    deleteCurrent();
    return item;
}

template <class T>
void LinkedList<T>::deleteCurrent() // 删除链表当前位置的结点
{
    Node<T> *p;
    if (currPtr == NULL)    // 如果表空或达到表尾则出错
    {
        cerr << "Invalid deletion!" << endl;
        exit(1);
    }
    if (prevPtr == NULL)    // 删除将发生在表头或链表之中
    {
        p = front;  // 保存头结点地址
        front = front->nextNode();  //将其从链表中分离
    }
    else    //分离prevPtr之后的一个内部结点,保存其地址
        p = prevPtr->deleteAfter();

    if (p == rear)  // 如果表尾结点被删除
    {
        rear = prevPtr; //新的表尾是prevPtr 
        position--; //position自减
    }
    currPtr = p->nextNode();    // 使currPtr越过被删除的结点
    freeNode(p);    // 释放结点,并
    size--; //使链表长度自减
}

template <class T>
T& LinkedList<T>::data()    //返回一个当前结点数值的引用
{
    if (size == 0 || currPtr == NULL)   // 如果链表为空或已经完成遍历则出错
    {
        cerr << "Data: invalid reference!" << endl;
        exit(1);
    }
    return currPtr->data;
}

template <class T>
void LinkedList<T>::clear() //清空链表
{
    Node<T> *currPosition, *nextPosition;
    currPosition = front;
    while (currPosition != NULL)
    {
        nextPosition = currPosition->nextNode(); //取得下一结点的地址
        freeNode(currPosition); //删除当前结点
        currPosition = nextPosition;    //当前指针移动到下一结点
    }
    front = rear = NULL;
    prevPtr = currPtr = NULL;
    size = 0;
    position = -1;
}
#endif  //LINKEDLIST_H


  • 示例6:

/*************************************************
**
**Description: 链表类应用举例
  从键盘输入10个整数,用这些整数值作为结点数据,生成一个链表,按顺序输出链表中
结点的数值。然后从键盘输入一个待查找整数,在链表中查找该整数,若找到则删除该整
数所在的结点(如果出现多次,全部删除),然后输出删除结点以后的链表。在程序结束
之前清空链表。
**
** Author:慕灵阁-wupke
** Time:2021-12-20
** Versions :8-6.cpp
** 
*
***************************************************/


#include <iostream>
#include "LinkedList.h"
#include"Node.h"
using namespace std;


int main() {
	LinkedList<int> list;

	//输入10个整数依次向表头插入
	for (int i = 0; i < 10; i++) {
		int item;
		cin >> item;
		list.insertFront(item);
	}

	//输出链表
	cout << "List: ";
	list.reset();
	//输出各结点数据,直到链表尾
	while (!list.endOfList()) {
		cout << list.data() << "  ";
		list.next();	//使游标指向下一个结点
	}
	cout << endl;

	//输入需要删除的整数
	int key;
	cout << "Please enter some integer needed to be deleted: ";
	cin >> key;

	//查找并删除结点
	list.reset();
	while (!list.endOfList()) {
		if (list.data() == key) 
			list.deleteCurrent();
		list.next();
	}

	//输出链表
	cout << "List: ";
	list.reset();
	//输出各结点数据,直到链表尾
	while (!list.endOfList()) {
		cout << list.data() << "  ";
		list.next();  //使游标指向下一个结点
	}
	cout << endl;
    system("pause");

	return 0;
}

  • 示例7:
/*************************************************
**
**Description: 栈的应用举例:实现一个简单的整数计算器(后置运算方式实现)

能够进行加、减、乘、除和乘方运算。
使用时算式采用后缀输入法,每个操作数、操作符之间都以空白符分隔。
例如,若要计算"3+5"则输入"3 5 +"。乘方运算符用"^"表示。
每次运算在前次结果基础上进行,若要将前次运算结果清除,可键入"c"。当键入"q"时程序结束。

** Author:慕灵阁-wupke
** Time:2021-12-20
** Versions :8-7.cpp
** 
*
***************************************************/

// calculator.cpp

#include"Calculator.h" // 声明计算器的相关操作

#include"Stack.h"  // 包含栈类模板定义文件
#include<iostream>
#include<sstream>
#include<cmath>

using namespace std;



//工具函数,用于将字符串转化为实数
inline double stringToDouble(const string &str){
    istringstream stream(str); //字符串输入流
    double result;
    stream >> result;
    return result;
}
void Calculator::enter(double num){   //将操作数num压入栈
    s.push(num);
}
bool Calculator::getTwoOperands(double &opnd1, double &opnd2){
    if (s.isEmpty()){  //检查栈是否为空
        cerr << " Missing operand ! " << endl;
        return false;
    }
    opnd1 = s.pop();//将右操作数弹出栈
    if (s.isEmpty()){  // 检查栈是否为空
        cerr << " Missing operand ! " << endl;
        return false;
    }
    opnd2 = s.pop();//将左操作数弹出栈
    return true;
}
void Calculator::compute(char op) {  //执行运算
    double operand1, operand2;
    bool result = getTwoOperands(operand1,operand2);

    if (result){//如果成功,执行结果并将结果压入栈
        switch (op)
        {
        case '+': s.push(operand1 + operand2);break;
        case '-': s.push(operand1 + operand2);break;        
        case '*': s.push(operand1 + operand2);break;
        case '/': if (operand1==0){  // 检查除数是否为零
            cerr << " Divided by 0 !!! " << endl;
            s.clear(); //除数为0时,清空栈

                }else
            s.push(operand2 / operand1);
                break;
        case '^': s.push(pow(operand2,operand1)); break;    
        default:  cerr << "Unrecognized operator!" << endl;
                break;
        }
        cout << "= " << s.peek() << " ";    //输出本次运算结果 
    }else
        s.clear();  //操作数不够,清空栈
}

void Calculator::run() { //读入并处理后缀表达式
    string str;
    while (cin >> str, str != "q") {
        switch(str[0]) {
        case 'c': s.clear(); break;
        case '-': //遇'-'需判断是减号还是负号
            if (str.size() > 1)
                enter(stringToDouble(str)); 
            else
                compute(str[0]);    
            break;
        case '+':   //遇到其它操作符时
        case '*':
        case '/':
        case '^':
            compute(str[0]);   break;
        default: //若读入的是操作数,转换为整型后压入栈
            enter(stringToDouble(str)); break;
        }
    }
}
void Calculator::clear() {  //清空操作数栈
    s.clear(); 
}


// 主函数

int main(){
    Calculator c;
    c.run();

    system("pause");
    return 0;
}





//Stack.h
/*    定义栈类的模板
栈的基本操作:初始化、入栈、出栈、清空栈、访问栈顶元素、检测栈的状态(满、空)
*/ 
#ifndef STACK_H
#define STACK_H
#include <cassert> 

//模板的定义,SIZE为栈的大小
template <class T, int SIZE = 50>  // T 类型参数
class Stack {
private:
	T list[SIZE];	//数组,用于存放栈的元素
	int top;	//栈顶位置(数组下标),指向栈顶的指针
public:
	Stack();	//构造函数,初始化栈
	void push(const T &item);	//将元素item压入栈
	T pop();	//将栈顶元素弹出栈
	void clear();	//将栈清空
	const T &peek() const;	//访问栈顶元素
	bool isEmpty() const;	//测试是否栈满
	bool isFull() const;	//测试是否栈空
};

//模板的实现
template <class T, int SIZE>
Stack<T, SIZE>::Stack() : top(-1) { }	//构造函数,栈顶初始化为-1

template <class T, int SIZE>
void Stack<T, SIZE>::push(const T &item) {	//将元素item压入栈
	assert(!isFull());	//如果栈满了,则报错
	list[++top] = item;	//将新元素压入栈顶
}

template <class T, int SIZE>
T Stack<T, SIZE>::pop() {	//将栈顶元素弹出栈
	assert(!isEmpty());	//如果栈为空,则报错
	return list[top--];	//返回栈顶元素,并将其弹出栈顶
}

template <class T, int SIZE>
const T &Stack<T, SIZE>::peek() const {	// // 仅读取栈顶的元素,判断是否为空
	assert(!isEmpty());	//如果栈为空,则报错
	return list[top];	//返回栈顶元素
}

template <class T, int SIZE>
bool Stack<T, SIZE>::isEmpty() const {	//测试栈是否空
	return top == -1;
}

template <class T, int SIZE>
bool Stack<T, SIZE>::isFull() const {	//测试是否栈满
	return top == SIZE - 1;
}

template <class T, int SIZE>
void Stack<T, SIZE>::clear() {	//清空栈
	top = -1;
}

#endif	//STACK_H







/*
计算器类及其相关成员函数的声明
*/

// calculator.h

#ifndef CALCULATOR_H
#define CALCULATOR_H

#include"Stack.h"  // 包含栈类模板定义文件

class Calculator{    // 计算器类
private:  // 服务计算器自身的函数
    Stack<double> s; // 操作数栈
    void enter(double num); //将操作数num压入栈
    // 连续将两个操作数弹出栈,放在opnd1 和 opnd2中
    bool getTwoOperands(double &opnd1, double &opnd2);
    void compute(char op); // 执行由操作符op指定的运算
public:// 外部接口
    void run();  //运行计算器程序
    void clear();  // 清空操作数栈
};

#endif



  • 示例8:
/*************************************************
**
**Description: Queue.h   队列的基础操作:队列类模板
**
** Author:慕灵阁-wupke
** Time:2021-12-20
** Versions :8-8.cpp
** 
*
***************************************************/
//Queue.h
#ifndef QUEUE_H
#define QUEUE_H
#include <cassert>

//类模板的定义
template <class T, int SIZE = 50>
class Queue {
private:
	int front, rear, count;	//队头指针、队尾指针、元素个数
	T list[SIZE];	//队列元素数组

public:
	Queue();          //构造函数,初始化队头指针、队尾指针、元素个数
	void insert(const T &item);	//新元素入队
	T remove();	//元素出队
	void clear();	//清空队列
	const T &getFront() const;	//访问队首元素

	//测试队列状态
	int getLength() const;	//求队列长度(元素个数)
	bool isEmpty() const;	//判队队列空否
	bool isFull() const;	//判断队列满否
};

//构造函数,初始化队头指针、队尾指针、元素个数
template <class T, int SIZE>
Queue<T, SIZE>::Queue() : front(0), rear(0), count(0) { }

template <class T, int SIZE>
void Queue<T, SIZE>::insert (const T& item) {	//向队尾插入元素(入队)
	assert(count != SIZE);
	count++;	//元素个数增1
	list[rear] = item;	//向队尾插入元素
	rear = (rear + 1) % SIZE;	//队尾指针增1,用取余运算实现循环队列
}

template <class T, int SIZE>
T Queue<T, SIZE>::remove() {	//删除队首元素,并返回该元素的值(出队)
	assert(count != 0);
	int temp = front;	//记录下原先的队首指针
    count--;			//元素个数自减
    front = (front + 1) % SIZE;	//队首指针增1。取余以实现循环队列
    return list[temp];	//返回首元素值
}

template <class T, int SIZE>
const T &Queue<T, SIZE>::getFront() const {	//访问队列首元素(返回其值)
	return list[front];
}

template <class T, int SIZE>
int Queue<T, SIZE>::getLength() const {	//返回队列元素个数
	return count;
}

template <class T, int SIZE>
bool Queue<T, SIZE>::isEmpty() const {	//测试队空否
	return count == 0;
}

template <class T, int SIZE>
bool Queue<T, SIZE>::isFull() const {	//测试队满否
	return count == SIZE;
}

template <class T, int SIZE>
void Queue<T, SIZE>::clear() {	//清空队列
	count = 0;
	front = 0; 
	rear = 0; 
}
    
#endif  //QUEUE_H


  • 示例9:
/*************************************************
**
**Description: 基本的数据排序和查找 、 各个基础的函数模板汇总
**

** Author:慕灵阁-wupke
** Time:2021-12-20
** Versions :8-9.cpp
** 
*
***************************************************/

/*
1、插入排序法函数模板(升序)
*/
#ifndef HEADER_H
#define HEADER9_H

//用直接插入排序法对数组A中的元素进行升序排列
template <class T>
void insertionSort(T a[], int n) {
	int i, j;
	T temp;

	//将下标为1~n-1的元素逐个插入到已排序序列中适当的位置
	for (int i = 1; i < n; i++) {
		//从a[i - 1]开始向a[0]方向扫描各元素,寻找适当位置插入a[i]
		int j = i;
		T temp = a[i];
		while (j > 0 && temp < a[j - 1]) {
			//逐个比较,直到temp >= a[j - 1]时,j便是应插入的位置。
			//若达到j == 0,则0是应插入的位置。
			a[j] = a[j - 1];    //将元素逐个后移,以便找到插入位置时可立即插入。
			j--;
		}
		//插入位置已找到,立即插入。
		a[j] = temp;
	}
}
#endif	//HEADER_H





/*
2、选择法排序函数模板
*/
// 选择法对数组a的n个元素进行排序
#ifndef HEADER_H
#define HEADER_H

//辅助函数:交换x和y的值
template <class T>
void mySwap(T &x, T &y) {
	T temp = x;
	x = y;
	y = temp;
}

//用选择法对数组a的n个元素进行排序
template <class T>
void selectionSort(T a[], int n) {
	for (int i = 0; i < n - 1; i++) {
		int leastIndex = i;	//最小元素之下标初值设为i
		for (int j = i + 1; j < n; j++)	//在元素a[i + 1]..a[n - 1]中逐个比较显出最小值
			if (a[j] < a[leastIndex])	//smallIndex始终记录当前找到的最小值的下标
				leastIndex = j;
		mySwap(a[i], a[leastIndex	]);	//将这一趟找到的最小元素与a[i]交换
	}
}
#endif	//HEADER_H




/*
3、冒泡排序函数模板
*/

#ifndef HEADER_H
#define HEADER_H

//辅助函数:交换x和y的值
template <class T>
void mySwap(T &x, T &y) {
	T temp = x;
	x = y;
	y = temp;
}

//用起泡法对数组A的n个元素进行排序
template <class T>
void bubbleSort(T a[], int n) {
	int i = n - 1;	// i是下一趟需参与排序交换的元素之最大下标
	while (i > 0) {	//持续排序过程,直到最后一趟排序没有交换发生,或已达n - 1趟
		int lastExchangeIndex = 0;	//每一趟开始时,设置交换标志为0(未交换)
		for (int j = 0; j < i; j++)	//每一趟对元素a[0]..a[i]进行比较和交换
			if (a[j + 1] < a[j]) {	//如果元素a[j + 1] < a[j],交换之
				mySwap(a[j], a[j + 1]);
				lastExchangeIndex = j;	//记录被交换的一对元素中较小的下标
			}
		i = lastExchangeIndex;	//将i设置为本趟被交换的最后一对元素中较小的下标
	}
}
#endif	//HEADER_H



/*
4、顺序查找函数模板
*/

#ifndef HEADER_H
#define HEADER_H

//用顺序查找法在数组list中查找值为key的元素
//若找到,返回该元素下标,否则返回-1
template <class T>
int seqSearch(const T list[], int n, const T &key) {
	for(int i = 0; i < n; i++)
		if (list[i] == key)
			return i;            
	return -1;                 
}

#endif	//HEADER_H

/*
5、二分查找函数模板
*/

#ifndef HEADER_H
#define HEADER_H

//用二分查找方法,在元素呈升序排列的数组list中查找值为key的元素
template <class T>
int binSearch(const T list[], int n, const T &key) {
	int low = 0;
	int high = n - 1;
	while (low <= high) {	//low <= high表示整个数组尚未查找完
		int mid = (low + high) / 2;	//求中间元素的下标
		if (key == list[mid])    
			return mid;		//若找到,返回下标
		else if (key < list[mid])
			high = mid - 1;	//若key < midvalue将查找范围缩小到数组的前一半
		else
			low = mid + 1;	//否则将查找范围缩小到数组的后一半
	}
	return -1;	//没有找到返回-1
}

#endif	//HEADER_H


  • 示例10:
/*************************************************
**
**Description:综合示例
改进:  如何允许用户随时动态添加新的账户:使用动态数组类模板 Arrary 来代替 c++ 预定义的数组类型
完整的代码分7个文件构建
** Author:慕灵阁-wupke
** Time:2021-12-20
** Versions :8-10.cpp
** 
*
***************************************************/
// 1、主函数 main.cpp
#include "account.h"
#include "Array.h"
#include <iostream>
using namespace std;

int main() {
	Date date(2008, 11, 1);	//起始日期
	Array<Account *> accounts(0);	//创建账户数组,元素个数为0
	cout << "(a)add account (d)deposit (w)withdraw (s)show (c)change day (n)next month (e)exit" << endl;
	char cmd;
	do {
		//显示日期和总金额
		date.show();
		cout << "\tTotal: " << Account::getTotal() << "\tcommand> ";

		char type;
		int index, day;
		double amount, credit, rate, fee;
		string id, desc;
		Account* account;

		cin >> cmd;
		switch (cmd) {
		case 'a':	//增加账户
			cin >> type >> id;
			if (type == 's') {
				cin >> rate;
				account = new SavingsAccount(date, id, rate);
			} else {
				cin >> credit >> rate >> fee;
				account = new CreditAccount(date, id, credit, rate, fee);
			}
			accounts.resize(accounts.getSize() + 1);
			accounts[accounts.getSize() - 1] = account;
			break;
		case 'd':	//存入现金
			cin >> index >> amount;
			getline(cin, desc);
			accounts[index]->deposit(date, amount, desc);
			break;
		case 'w':	//取出现金
			cin >> index >> amount;
			getline(cin, desc);
			accounts[index]->withdraw(date, amount, desc);
			break;
		case 's':	//查询各账户信息
			for (int i = 0; i < accounts.getSize(); i++) {
				cout << "[" << i << "] ";
				accounts[i]->show();
				cout << endl;
			}
			break;
		case 'c':	//改变日期
			cin >> day;
			if (day < date.getDay())
				cout << "You cannot specify a previous day";
			else if (day > date.getMaxDay())
				cout << "Invalid day";
			else
				date = Date(date.getYear(), date.getMonth(), day);
			break;
		case 'n':	//进入下个月
			if (date.getMonth() == 12)
				date = Date(date.getYear() + 1, 1, 1);
			else
				date = Date(date.getYear(), date.getMonth() + 1, 1);
			for (int i = 0; i < accounts.getSize(); i++)
				accounts[i]->settle(date);
			break;
		}
	} while (cmd != 'e');

	for (int i = 0; i < accounts.getSize(); i++)
		delete accounts[i];

    system("pause");
	return 0;
}




//2、account.h
#ifndef __ACCOUNT_H__
#define __ACCOUNT_H__
#include "date.h"
#include "accumulator.h"
#include <string>

class Account { //账户类
private:
	std::string id;	//帐号
	double balance;	//余额
	static double total; //所有账户的总金额
protected:
	//供派生类调用的构造函数,id为账户
	Account(const Date &date, const std::string &id);
	//记录一笔帐,date为日期,amount为金额,desc为说明
	void record(const Date &date, double amount, const std::string &desc);
	//报告错误信息
	void error(const std::string &msg) const;
public:
	const std::string &getId() const { return id; }
	double getBalance() const { return balance; }
	static double getTotal() { return total; }
	//存入现金,date为日期,amount为金额,desc为款项说明
	virtual void deposit(const Date &date, double amount, const std::string &desc) = 0;
	//取出现金,date为日期,amount为金额,desc为款项说明
	virtual void withdraw(const Date &date, double amount, const std::string &desc) = 0;
	//结算(计算利息、年费等),每月结算一次,date为结算日期
	virtual void settle(const Date &date) = 0;
	//显示账户信息
	virtual void show() const;
};

class SavingsAccount : public Account { //储蓄账户类
private:
	Accumulator acc;	//辅助计算利息的累加器
	double rate;		//存款的年利率
public:
	//构造函数
	SavingsAccount(const Date &date, const std::string &id, double rate);
	double getRate() const { return rate; }
	virtual void deposit(const Date &date, double amount, const std::string &desc);
	virtual void withdraw(const Date &date, double amount, const std::string &desc);
	virtual void settle(const Date &date);
};

class CreditAccount : public Account { //信用账户类
private:
	Accumulator acc;	//辅助计算利息的累加器
	double credit;		//信用额度
	double rate;		//欠款的日利率
	double fee;			//信用卡年费

	double getDebt() const {	//获得欠款额
		double balance = getBalance();
		return (balance < 0 ? balance : 0);
	}
public:
	//构造函数
	CreditAccount(const Date &date, const std::string &id, double credit, double rate, double fee);
	double getCredit() const { return credit; }
	double getRate() const { return rate; }
	double getFee() const { return fee; }
	double getAvailableCredit() const {	//获得可用信用
		if (getBalance() < 0) 
			return credit + getBalance();
		else
			return credit;
	}
	virtual void deposit(const Date &date, double amount, const std::string &desc);
	virtual void withdraw(const Date &date, double amount, const std::string &desc);
	virtual void settle(const Date &date);
	virtual void show() const;
};

#endif //__ACCOUNT_H__





//3、account.cpp
#include "account.h"
#include <cmath>
#include <iostream>
using namespace std;

double Account::total = 0;

//Account类的实现
Account::Account(const Date &date, const string &id)
	: id(id), balance(0) {
	date.show();
	cout << "\t#" << id << " created" << endl;
}

void Account::record(const Date &date, double amount, const string &desc) {
	amount = floor(amount * 100 + 0.5) / 100;	//保留小数点后两位
	balance += amount;
	total += amount;
	date.show();
	cout << "\t#" << id << "\t" << amount << "\t" << balance << "\t" << desc << endl;
}

void Account::show() const {
	cout << id << "\tBalance: " << balance;
}

void Account::error(const string &msg) const {
	cout << "Error(#" << id << "): " << msg << endl;
}

//SavingsAccount类相关成员函数的实现
SavingsAccount::SavingsAccount(const Date &date, const string &id, double rate)
	: Account(date, id), rate(rate), acc(date, 0) { }

void SavingsAccount::deposit(const Date &date, double amount, const string &desc) {
	record(date, amount, desc);
	acc.change(date, getBalance());
}

void SavingsAccount::withdraw(const Date &date, double amount, const string &desc) {
	if (amount > getBalance()) {
		error("not enough money");
	} else {
		record(date, -amount, desc);
		acc.change(date, getBalance());
	}
}

void SavingsAccount::settle(const Date &date) {
	if (date.getMonth() == 1) {	//每年的一月计算一次利息
		double interest = acc.getSum(date) * rate
			/ (date - Date(date.getYear() - 1, 1, 1));
		if (interest != 0)
			record(date, interest, "interest");
		acc.reset(date, getBalance());
	}
}

//CreditAccount类相关成员函数的实现
CreditAccount::CreditAccount(const Date& date, const string& id, double credit, double rate, double fee)
	: Account(date, id), credit(credit), rate(rate), fee(fee), acc(date, 0) { }

void CreditAccount::deposit(const Date &date, double amount, const string &desc) {
	record(date, amount, desc);
	acc.change(date, getDebt());
}

void CreditAccount::withdraw(const Date &date, double amount, const string &desc) {
	if (amount - getBalance() > credit) {
		error("not enough credit");
	} else {
		record(date, -amount, desc);
		acc.change(date, getDebt());
	}
}

void CreditAccount::settle(const Date &date) {
	double interest = acc.getSum(date) * rate;
	if (interest != 0)
		record(date, interest, "interest");
	if (date.getMonth() == 1)
		record(date, -fee, "annual fee");
	acc.reset(date, getDebt());
}

void CreditAccount::show() const {
	Account::show();
	cout << "\tAvailable credit:" << getAvailableCredit();
}




//4、accumulator.h
#ifndef __ACCUMULATOR_H__
#define __ACCUMULATOR_H__
#include "date.h"

class Accumulator {	//将某个数值按日累加
private:
	Date lastDate;	//上次变更数值的时期
	double value;	//数值的当前值
	double sum;		//数值按日累加之和
public:
	//构造函数,date为开始累加的日期,value为初始值
	Accumulator(const Date &date, double value)
		: lastDate(date), value(value), sum(0) { }

	//获得到日期date的累加结果
	double getSum(const Date &date) const {
		return sum + value * (date - lastDate);
	}

	//在date将数值变更为value
	void change(const Date &date, double value) {
		sum = getSum(date);
		lastDate = date;
		this->value = value;
	}

	//初始化,将日期变为date,数值变为value,累加器清零
	void reset(const Date &date, double value) {
		lastDate = date;
		this->value = value;
		sum = 0;
	}
};

#endif //__ACCUMULATOR_H__






//5、Array.h
#ifndef ARRAY_H
#define ARRAY_H

#include <cassert>

//数组类模板定义
template <class T> 
class Array {
private:
	T* list;	//T类型指针,用于存放动态分配的数组内存首地址
	int size;	//数组大小(元素个数)
public:
	Array(int sz = 50);			//构造函数
	Array(const Array<T> &a);	//拷贝构造函数
	~Array();	//析构函数
	Array<T> & operator = (const Array<T> &rhs); //重载"="使数组对象可以整体赋值
	T & operator [] (int i);	//重载"[]",使Array对象可以起到C++普通数组的作用
	const T & operator [] (int i) const;	//"[]"运算符的const版本
	operator T * ();	//重载到T*类型的转换,使Array对象可以起到C++普通数组的作用
	operator const T * () const;	//到T*类型转换操作符的const版本
	int getSize() const;	//取数组的大小
	void resize(int sz);	//修改数组的大小
};

//构造函数
template <class T>
Array<T>::Array(int sz) {
	assert(sz >= 0);	//sz为数组大小(元素个数),应当非负
	size = sz;	// 将元素个数赋值给变量size
	list = new T [size];	//动态分配size个T类型的元素空间
}

//析构函数
template <class T>
Array<T>::~Array() {
	delete [] list;
}

//拷贝构造函数
template <class T>
Array<T>::Array(const Array<T> &a) {
	//从对象x取得数组大小,并赋值给当前对象的成员
	size = a.size;
	//为对象申请内存并进行出错检查
	list = new T[size];	// 动态分配n个T类型的元素空间
	//从对象X复制数组元素到本对象  
	for (int i = 0; i < size; i++)
		list[i] = a.list[i];
}

//重载"="运算符,将对象rhs赋值给本对象。实现对象之间的整体赋值
template <class T>
Array<T> &Array<T>::operator = (const Array<T>& rhs) {
	if (&rhs != this) {
		//如果本对象中数组大小与rhs不同,则删除数组原有内存,然后重新分配
		if (size != rhs.size) {
			delete [] list;		//删除数组原有内存
			size = rhs.size;	//设置本对象的数组大小
			list = new T[size];	//重新分配n个元素的内存
		}
		//从对象X复制数组元素到本对象  
		for (int i = 0; i < size; i++)
			list[i] = rhs.list[i];
	}
	return *this;	//返回当前对象的引用
}

//重载下标运算符,实现与普通数组一样通过下标访问元素,并且具有越界检查功能
template <class T>
T &Array<T>::operator[] (int n) {
	assert(n >= 0 && n < size);	//检查下标是否越界
	return list[n];			//返回下标为n的数组元素
}

template <class T>
const T &Array<T>::operator[] (int n) const {
	assert(n >= 0 && n < size);	//检查下标是否越界
	return list[n];			//返回下标为n的数组元素
}

//重载指针转换运算符,将Array类的对象名转换为T类型的指针,
//指向当前对象中的私有数组。
//因而可以象使用普通数组首地址一样使用Array类的对象名
template <class T>
Array<T>::operator T * () {
	return list;	//返回当前对象中私有数组的首地址
}

template <class T>
Array<T>::operator const T * () const {
	return list;	//返回当前对象中私有数组的首地址
}

//取当前数组的大小
template <class T>
int Array<T>::getSize() const {
	return size;
}

// 将数组大小修改为sz
template <class T>
void Array<T>::resize(int sz) {
	assert(sz >= 0);	//检查sz是否非负
	if (sz == size)	//如果指定的大小与原有大小一样,什么也不做
		return;
	T* newList = new T [sz];	//申请新的数组内存
	int n = (sz < size) ? sz : size;	//将sz与size中较小的一个赋值给n
	//将原有数组中前n个元素复制到新数组中
	for (int i = 0; i < n; i++)
		newList[i] = list[i];
	delete[] list;		//删除原数组
	list = newList;	// 使list指向新数组
	size = sz;	//更新size
}
#endif  //ARRAY_H




//6、date.cpp
#include "date.h"
#include <iostream>
#include <cstdlib>
using namespace std;

namespace {	//namespace使下面的定义只在当前文件中有效
	//存储平年中某个月1日之前有多少天,为便于getMaxDay函数的实现,该数组多出一项
	const int DAYS_BEFORE_MONTH[] = { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 365 };
}

Date::Date(int year, int month, int day) : year(year), month(month), day(day) {
	if (day <= 0 || day > getMaxDay()) {
		cout << "Invalid date: ";
		show();
		cout << endl;
		exit(1);
	}
	int years = year - 1;
	totalDays = years * 365 + years / 4 - years / 100 + years / 400
		+ DAYS_BEFORE_MONTH[month - 1] + day;
	if (isLeapYear() && month > 2) totalDays++;
}

int Date::getMaxDay() const {
	if (isLeapYear() && month == 2)
		return 29;
	else
		return DAYS_BEFORE_MONTH[month]- DAYS_BEFORE_MONTH[month - 1];
}

void Date::show() const {
	cout << getYear() << "-" << getMonth() << "-" << getDay();
}





//7、date.h
#ifndef __DATE_H__
#define __DATE_H__

class Date {	//日期类
private:
	int year;		//年
	int month;		//月
	int day;		//日
	int totalDays;	//该日期是从公元元年1月1日开始的第几天

public:
	Date(int year, int month, int day);	//用年、月、日构造日期
	int getYear() const { return year; }
	int getMonth() const { return month; }
	int getDay() const { return day; }
	int getMaxDay() const;		//获得当月有多少天
	bool isLeapYear() const {	//判断当年是否为闰年
		return year % 4 == 0 && year % 100 != 0 || year % 400 == 0;
	}
	void show() const;			//输出当前日期
	//计算两个日期之间差多少天	
	int operator - (const Date& date) const {
		return totalDays - date.totalDays;
	}
};

#endif //__DATE_H__




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值