CPPDay08 模板(函数模板,模板函数,类模板,模板类)+如何用模板来写一个自己的栈(顺序栈,链式栈)

本文深入探讨了C++中的模板编程,包括函数模板和类模板的使用,并通过实例展示了如何利用类模板实现顺序栈和链式栈,提高了代码的复用性和开发效率。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

0x00模板:为了提升开发效率

0x01用类模板来写一个自己的栈:

1.顺序栈:

2.链式栈


0x00模板:为了提升开发效率

#include <iostream>
using namespace std;
//函数模板
template<typename T>//泛型可以对应任意类型 ,typename换成class也可以,不建议class和typename混合使用。
T add(T a ,T b){
	return a+b;
}
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
	//模板函数
    cout<<add(1,2)<<endl;//隐式调用模板,自动传
	cout<<add<double>(1.0,2.0)<<endl;//显式调用模板,<>里面的可以理解为参数,
//显示调用,可以两个参数都指定,也可以只指定第一个,但是不可以指定第二个。
	cout<<add('A',' ')<<endl;//隐式调用模板
	return 0;
}
  1. 基于泛型(泛型指的是编译器能够自动识别类型)
  2. 函数模板(区分)
    1. 函数模板:只有一个
    2. 模板函数:调用函数时,根据实参类型决定函数参数类型的函数。(可以有无限个,我们先有一个函数模板,然后可以用这个模板去生成无限多个模板函数,每一个函数又可以被调用无数次)
  3. 类模板:类模板生成模板类后,模板类中还有有函数模板,模板类还要生成许多对象,每个对象还要生成模板函数。
    1. 注意:
      1. 类模板只能显示调用,不能隐式调用。
      2. 类模板的函数声明和函数都必须放在.h.文件中,.h中声明,.cpp中实现,其他的函数之所以能.h中声明,.cpp中实现,是因为所有的函数都是extern过去的,而使用了类模板的函数,是不能extern的,没有办法扩展作用域
      3. 定义成员函数时,类名后面要加泛型参数列表
      4. 类模板中有内部类,需要在内模板之外使用内部类类型,要写typename加外部类作用域限定方式
    2. 
      
      #pragma once
      #include <string>
      #include <iostream>
      using namespace std;
      template<class T>//类模板声明 
      //模板类 
      class Car
      {
      	string name;
      	T score;
      	public:
      		Car(){cout<<"无参构造"<<endl; 
      		}
      		~Car(){cout<<"析构器"<<endl; 
      		}
      		Car(string n,T s);
      		void show();
      	protected:
      };
      template<class T>//类模板声明
      void Car<T>::show(){
      	cout<<"这是一辆价值"<<score<<"万的"<<name<<endl; 
      }
      template<class T>
      Car<T>::Car(string n,T s)//模板类中函数模板 
      {
      	name=n;
      	score=s;
      	cout<<"有参构造"<<endl; 
      }
      
      
      #include <iostream>
      #include "Car.h"
      /* run this program using the console pauser or add your own getch, system("pause") or input loop */
      
      int main(int argc, char** argv) {
      	
      	Car<int> c("劳斯莱斯幻影",1000);//模板类的一个对象 
      	Car<double>cd("雪佛兰A3",100000.0);//模板类的另一个对象 
      	c.show();
      	cd.show();
      	
      	while(1);
      	return 0;
      }

       

0x01用类模板来写一个自己的栈:

1.顺序栈:

#pragma once
#include <iostream>
#include <string>
using namespace std;
template <class T>
//顺序栈 ,数据是放在相邻的内存段里的 

class MyStack{
	 T* pBuff;
	 size_t size;
	void _clear();
public:
	MyStack();
	~MyStack();
	void clear();
	//数据入栈 
	void push(const T& data);//如果不传引用,这里就会临时构建一个T对象浪费。 
    //遍历整个栈 
	void  travel(void) const;
	//返回元素个数
	size_t getSize(void) const{return this->size;}
	//判断栈是否为空
	bool isEmpty(void)const {return (size==0);}
	//获取栈顶元素
	const T getTop(void)const{return pBuff[size-1];}
	//出栈
	void pop(); 
 
}; 

template <class T>//数据入栈 
void MyStack<T>::push(const T& data){
	//1 开内存
	T* pNew = new T[size + 1];//开原来大小加1的内存 
	//2  检查原有内存段是否有数据
	if(pBuff){
		//拷贝原有内存段
		memcpy(pNew,pBuff,sizeof(T)*size); 
		//释放原有内存段
		delete[] pBuff;
		//puBuff指向新开内存段
		pBuff=pNew;
		//数据存入后size++
		 pBuff[size++]=data;
	} 
	
	//3 如果有 先把有的数据拷贝过来, 释放原有内存段
	
	//4 如果没有 pBuff 指向新开内存段
	else{
		//pBuff 指向新开内存段
		pBuff = pNew;
		//数据存入size++ 
		pBuff[size++]=data;
	}
	//5 数据存入 size增加 
 
} 
template <class T>
void  MyStack<T>::travel(void) const{
     cout<<"stack:";
	 for(size_t i=0;i<size;i++){
     	cout<<pBuff[i]<<' ';
	 }
	 cout<<endl;

}

template <class T>
void MyStack<T>::pop(){
	//1判断栈中元素个数 
	if(pBuff==NULL)return;
	//2
	if(size==1){
		//释放内存 
        delete[]pBuff;
        //size减少 
		size--;		
	}
	else{
	//新开内存
	T* pNew=new T[size-1];  
	//数据拷贝
	memcpy(pNew,pBuff,sizeof(T)*(size-1));
	delete[] pBuff;
	//pBuff指向新开内存
	pBuff=pNew;
	//size减少 
	
	size--;
	} 
	
}

template <class T>
void MyStack<T>::clear(){
	_clear();
	
}
template <class T>
void MyStack<T>::_clear(){
	if(pBuff){
		delete[] pBuff;
		pBuff=NULL;
	}
}


template <class T>
MyStack<T>::MyStack(){
	pBuff=NULL;
	size=0;
	
}
template <class T>
MyStack<T>::~MyStack(){
  _clear();
}
 

主函数:

#include <iostream>
#include "CMyStack.h"
using namespace std;
/* run this program using the console pauser or add your own getch, system("pause") or input loop */

int main(int argc, char** argv) {
	
	MyStack<int> int_stack;
	MyStack<double> double_stack;
	for(int i=0;i<10;i++){
		int_stack.push(i+1);
		double_stack.push(i+1.1);
	}
	int_stack.travel();
	double_stack.travel();
	for(int i=0;i<10;i++){
		int_stack.pop();
		double_stack.pop();
		int_stack.travel();
		double_stack.travel();
	}
	
	return 0;
}

2.链式栈

#pragma once
#include <iostream>
#include <string>
using namespace std;

template <class T>
//链式栈 
class MyStack{
	struct node{
		T data;
		struct node* next;
	};//节点类型要做成内部类 
	node *head;
	size_t size;
public:
	void push(const T& data);
	MyStack();
	void pop();

private:
	void delHeadNode();
	node*_CreateNode(const T&data);
		
};
template <class T>
void MyStack<T>::pop(){
	if(head==NULL)return;
  if(size==1) {//只有一个元素 
  	delete head;
  	head=NULL;
  }
  else{//有多个元素 
  	 node*temp=head;//保存头结点地址 
  	 head=head->next;//第二个节点成为头节点 
  	 delete temp;//释放 
  	 temp=NULL;
     
  }
  size--;
}
template <class T>
void MyStack<T>::delHeadNode(){
  if(head==NULL)return;
  if(size==1) {//只有一个元素 
  	delete head;
  	head=NULL;
  }
  else{//有多个元素 
  	 node*temp=head;//保存头结点地址 
  	 head=head->next;//第二个节点成为头节点 
  	 delete temp;//释放 
  	 temp=NULL;
  }
  size--;
}

template <class T>
MyStack<T>::MyStack(){
	head=NULL;
	size=0;
	
}
//创建一个链表结点 
template <class T>
typename MyStack<T>::node* MyStack<T>::_CreateNode(const T&data){//注意:如果是内部类中使用泛型,要加typename以及作用域限定符 
	node* pNew= new node;
	pNew->data =data;
	pNew->next= NULL;
	return pNew;
}
template<class T>
//入栈 头插法
 
void MyStack<T>::push(const T&data) {
   node*pNew =_CreateNode(data);
   //判断是否是空栈
   if(head){//不是空栈 
   	 pNew->next=head;//新节点的下一个节点是原来的第一个节点。 
   	 head =pNew;//新节点成为第一个节点。
	 
   	
   } 
  else{//空栈
      head=pNew; 
  }
  size++; 
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值