目录
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;
}
- 基于泛型(泛型指的是编译器能够自动识别类型)
- 函数模板(区分)
- 函数模板:只有一个
- 模板函数:调用函数时,根据实参类型决定函数参数类型的函数。(可以有无限个,我们先有一个函数模板,然后可以用这个模板去生成无限多个模板函数,每一个函数又可以被调用无数次)
- 类模板:类模板生成模板类后,模板类中还有有函数模板,模板类还要生成许多对象,每个对象还要生成模板函数。
- 注意:
- 类模板只能显示调用,不能隐式调用。
- 类模板的函数声明和函数都必须放在.h.文件中,.h中声明,.cpp中实现,其他的函数之所以能.h中声明,.cpp中实现,是因为所有的函数都是extern过去的,而使用了类模板的函数,是不能extern的,没有办法扩展作用域
- 定义成员函数时,类名后面要加泛型参数列表
- 类模板中有内部类,需要在内模板之外使用内部类类型,要写typename加外部类作用域限定方式
-
#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++;
}