函数模板,类模板

模板功能提供了在函数和类中将类型作为参数的能力,可以设计具有通用类型的函数和类,而编译器在编译时会将通用类型确定为具体类型。

如max()函数:需要比较两个int,double, char, string,需要写四个重载函数

C++允许定义具有通用类型的函数模板

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
#include <string>using namespace std;// 定义函数模板
template<typename T>
T maxValue(T a, T b)
{if(a>=b)return a;elsereturn b;
} int main(int argc, char *argv[])
{cout << "Maxium between 1 and 3 is " << maxValue(1,3) << endl;cout << "Maxium between 1.6 and 0.3 is " << maxValue(1.6,0.3) << endl;cout << "Maxium between a and c is " << maxValue('a','c') << endl;cout << "Maxium between \"NFC\" and \"NBA\" is " << maxValue(string("NFC"), string("NBA")) << endl;return 0;
}

关键字:template, 后面是参数列表,参数列表必须有关键字typename

在进行string类型的比较时,如果使用maxValue("NFC", "NBA")的话,参数为C字符串,传递给函数的参数是两个字符串的地址,所以比较的是地址。

例子:一个通用的排序函数:

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <time.h>
#include <string>using namespace std;// 定义函数模板 一个通用的排序函数
template<typename T>
void sortedArray(T array[], int SIZE)
{// 选择排序for(int i=0; i<SIZE-1; i++){T current_min = array[i];int current_min_index = i;for(int j=i+1; j<SIZE; j++){if(array[j]<current_min){current_min = array[j];current_min_index = j;}}if(current_min_index!=i){T tmp = array[i];array[i] = array[current_min_index];array[current_min_index] = tmp;}}
}template<typename T>
void printArray(T array[], int SIZE)
{for(int i=0; i<SIZE; i++){cout << setw(5) << array[i];}cout << endl;
}int main(int argc, char *argv[])
{int a[] = {3, 5, 2, 6, 9, 4};sortedArray(a, 6);printArray(a, 6); double b[] = {6.3, 4.1, 4.2, 7.9, 0.6, 8.8};sortedArray(b, 6);printArray(b, 6);string c[] = {"lanzhou", "student", "wangzi"};sortedArray(c, 3);printArray(c, 3);  return 0;
}

模板类:

除了用类型参数定义模板函数,也可以用类型参数定义模板类,类型参数可以用于类中任何地方

将StackOfInteger修改为通用 的Stack类:  // 对于模板类,将类的定义和实现放在一起更为安全,有的编译器不支持将类的定义和实现分离!

声明模板类对象时,必须指定函数类型

模板类与普通类区别总结:

1. 定义和实现放在一起  h文件

2.类的定义,前面必须有模板前缀   template<typename T>

3.类的实现中每个构造函数和成员函数之前都要有模板前缀 template<typename T>, 类的名称为ClassName<T>::methods

4.声明类的对象时,必须指定参数类型 Class<int/string> object

修改intStack为模板类:

code:

stack.h

// stack 类的定义
#ifndef STACK_H
#define STACK_H
using namespace std;template<typename T>
class Stack
{private: int size;T element[100];public:Stack();     // 构造函数bool isEmpty() const;    // 只读函数T peek() const;   //返回栈底的元素void push(T value);   // 入栈T pop();   // 出栈int getSize() const;
};
// 类的实现
// 类的构造函数和成员函数的实现与模板函数一样,前面要模板前缀,同时类名为Stack<T>
template<typename T>
Stack<T>::Stack()
{size = 0;
}template<typename T>
bool Stack<T>::isEmpty() const
{return size==0;
}template<typename T>
T Stack<T>::peek() const
{return element[size-1];   // 只读函数不能改变数据域
}template<typename T>
void Stack<T>::push(T value)
{element[size++] = value;
}template<typename T>
T Stack<T>::pop()
{if(isEmpty())cout << "The stack is stack" << endl;elsereturn element[--size];
}template<typename T>
int Stack<T>::getSize() const
{return size;
}#endif 

main.cpp

#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>   // 将数字转化为字符串
#include <algorithm>
#include "E:\back_up\code\c_plus_code\chapter8\external_file\course.h"
#include "E:\back_up\code\c_plus_code\chapter8\external_file\stack.h"using namespace std;int main(int argc, char *argv[])
{Stack<int> int_stack;  //声明模板类对象。必须指定类型for(int i=0; i< 10; i++){int_stack.push(i);} cout << "Peek int_stack " << int_stack.peek() << endl;while(!int_stack.isEmpty()){cout << int_stack.pop() << " ";}cout << endl;Stack<string> string_stack;string_stack.push("Nanhudadao");string_stack.push("Helloworld");string_stack.push("stongarm");while(!string_stack.isEmpty()){cout << string_stack.pop() << " ";}cout << endl;return 0;
}

可以定义一个输出栈中元素的函数模板,函数参数是栈的引用:

#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>   // 将数字转化为字符串
#include <algorithm>
#include "E:\back_up\code\c_plus_code\chapter8\external_file\course.h"
#include "E:\back_up\code\c_plus_code\chapter8\external_file\stack.h"using namespace std;// 定义一个输出栈中元素的函数
template<typename T>
void printStack(Stack<T>& stack)   // 参数
{while(!stack.isEmpty()){cout << stack.pop() << " ";}cout << endl;
}int main(int argc, char *argv[])
{Stack<int> int_stack;  //声明模板类对象。必须指定类型for(int i=0; i< 10; i++){int_stack.push(i);} cout << "Peek int_stack " << int_stack.peek() << endl;printStack(int_stack);Stack<string> string_stack;string_stack.push("Nanhudadao");string_stack.push("Helloworld");string_stack.push("stongarm");printStack(string_stack);return 0;
}

可以为模板类中的类型参数指定一个默认的参数类型作为缺省类型,还可以使用非类型参数。

template<typename T=int, int capacity>  // 默认的参数类型是int
class Stack
{private:T element[capacity];int size;public:....
}void main()
{Stack<int, 500> int_stack;   // 500哥元素的栈
}

Stack<> stack;

Stack类的改进:

前面的Stack中数据存储在一个固定大小的数组中,不合理。

改进方法:预先分配一个较小的空间,如果需要,再动态增加数组的大小

思路: 增加一个新的属性capacity,表示保存元素的数组的当前大小,构造函数中先创建一个小的数组,当数组已满时,就增加数组的大小来保存新的元素:

如何增加数组的大小呢?

创建一个新的更大的数组,和将原数组中的元素复制过来,将旧的数组删掉即可。

实现代码

stack_improve.h

#ifndef STACK_IMPRPVE_H
#define STACK_IMPROVE_H
#include <iostream>
using namespace std;template<typename T=int>
class Stack_improve
{private:T* elements;int size;int capacity;void ensureCapacity();public:Stack_improve();   // 构造函数Stack_improve(const Stack_improve&);   // 拷贝构造函数~Stack_improve();    // 析构函数bool isEmpty() const;T peek() const;void push(T value);T pop();int getSize() const;
};template<typename T>
Stack_improve<T>::Stack_improve()
{size = 0;        // 元素个数 capacity = 10;   // 栈的初始容量的大小为10 elements = new T[capacity];
}template<typename T>
Stack_improve<T>::Stack_improve(const Stack_improve& stack)  // 拷贝构造函数,实现深拷贝
{elements = new T[stack.capacity];   // 分配独立的存储空间size = stack.size;capacity = stack.capacity;for(int i=0; i<size; i++){elements[i] = stack.elements[i];}      }template<typename T>
Stack_improve<T>::~Stack_improve()
{delete []elements;
}template<typename T>
bool Stack_improve<T>::isEmpty() const
{return size==0;
}template<typename T>
T Stack_improve<T>::peek() const
{return elements[size-1];
}template<typename T>
void Stack_improve<T>::push(T value)
{ensureCapacity();elements[size++] = value;
}template<typename T>
T Stack_improve<T>::pop()
{return elements[--size];
}template<typename T>
int Stack_improve<T>::getSize() const
{return size;
}template<typename T>
void Stack_improve<T>::ensureCapacity()
{if(size>=capacity){T* old  = elements;capacity = 2 * size;  // 改变capacity的大小elements = new T[capacity];// 将旧的数组的值复制过来for(int i=0; i<size; i++){elements[i] = old[i]; } delete [] old;}
}#endif

main.cpp

#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>   // 将数字转化为字符串
#include <algorithm>
#include "E:\back_up\code\c_plus_code\chapter8\external_file\stack_improve.h"using namespace std;// 定义一个输出栈中元素的函数
template<typename T>
void printStack(Stack_improve<T>& stack)
{while(!stack.isEmpty()){cout << stack.pop() << " ";}cout << endl;
}int main(int argc, char *argv[])
{Stack_improve<int> int_stack;  //声明模板类对象。必须指定类型for(int i=0; i< 10; i++){int_stack.push(i);} cout << "Peek int_stack " << int_stack.peek() << endl;printStack(int_stack);Stack_improve<string> string_stack;string_stack.push("Nanhudadao");string_stack.push("Helloworld");string_stack.push("stongarm");printStack(string_stack);return 0;
}

c++向量类:

C++提供了通用类Vector.用于存储列表对象    #include<vector>

vector类中的常用函数:

vector<type> Vname()
vector<type> Vname(size)

push_back(element)    // 追加append()

pop_back()                 // 删除最后后一个元素

size()

at(index)

empty()

clear()

swap()   // 交换两个向量中的内容

#include <iostream>
#include <vector>
#include <string>
using namespace std;int main(int argc, char *argv[])
{// 使用atoi将字符串转化为intvector<int> intvect;for(int i=0; i<10; i++){intvect.push_back(i*i);}cout << "Numbers in the vector: " << endl;for(int i=0; i<intvect.size(); i++){cout << intvect[i] << " ";}cout << endl;intvect.pop_back();   // 不返回值for(int i=0; i<intvect.size(); i++){cout << intvect[i] << " ";}cout << endl;vector<string> stringvect;stringvect.push_back("hello");stringvect.push_back("Nananan");stringvect.push_back("Crypto");cout << stringvect.empty() << endl;return 0;
}

随机选取四种扑克牌:(将数组替换成向量)

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>     // 随机数  ctime
#include <string>
#include <vector>using namespace std;
const int number_of_cards = 52;
string suits[4] = {"Spades", "Hearts", "Diamond", "Clubs"};
string ranks[] = {"Ace", "2", "3", "4", "5", "6", "7", "8", "9", "10", "Jack", "Queen", "King"};int main(int argc, char *argv[])
{vector<int> deck(number_of_cards);// initializefor(int i=0; i<number_of_cards; i++){deck[i] = i;}   srand(time(0));  // shufflefor(int i=0; i<number_of_cards; i++){int index = rand() % number_of_cards;int temp = deck[i];deck[i] = deck[index];deck[index] = temp;}// select four cardsfor(int i=0; i<4; i++){cout << ranks[deck[i]%13] << " of " << suits[deck[i]/13] << endl;}return 0;
}

二维数组也可以用向量表示:

#include <iostream>
#include <iomanip>
#include <cstdlib>
#include <ctime>
#include <string>
#include <vector>using namespace std;void printMatrix(vector<vector<int > >& matrix)
{for(int i=0; i<matrix.size(); i++){for(int j=0; j<matrix[i].size(); j++){cout << matrix[i][j] << " ";}cout << endl;}
} int main(int argc, char *argv[])
{ vector<vector<int> > matrix(4);   // vector<vector<int> >必须有空格 for(int i=0; i<matrix.size(); i++){matrix[i] = vector<int>(3);    // 二维向量初始化 }for(int i=0; i<matrix.size(); i++){for(int j=0; j<matrix[i].size(); j++){matrix[i][j] = i+j;}}printMatrix(matrix);return 0;
}

用栈实现表达式计算:
如: 51+(54*93+2))=?

#include <iostream>
#include <string>
#include <iomanip>
#include <sstream>   // 将数字转化为字符串
#include <algorithm>
#include "E:\back_up\code\c_plus_code\chapter8\external_file\course.h"
#include "E:\back_up\code\c_plus_code\chapter8\external_file\stack.h"
#include "E:\back_up\code\c_plus_code\chapter8\external_file\stack_improve.h"
#include <vector>
#include <cctype>   // include isdigit()using namespace std;// define function split() for split expression into number, operarot, return a vector
vector<string> split(const string& expression);
// calculate the expression
int evaluateExpression(const string& expression);     // return the result
// process the stack
void processAnOperator(Stack_improve<int> operandStack, Stack_improve<char> operator_stack);// 定义一个输出栈中元素的函数
template<typename T>
void printStack(Stack_improve<T>& stack)
{while(!stack.isEmpty()){cout << stack.pop() << " ";}cout << endl;
}int main(int argc, char *argv[])
{string expre;cout << "Enter the expression: " << endl;getline(cin, expre);cout << "Expression " << expre << " = " << evaluateExpression(expre) << endl;return 0;}// define function split() for split expression into number, operarot
vector<string> split(const string& expression)
{vector<string> v;string numberString;for(unsigned i=0; i<expression.length(); i++){if(isdigit(expression[i]))   // 开始的时候碰到数字 包含是多位数的可能 numberString.append(1, expression[i]);   // 将数字追加在numberString后 else{if(numberString.size()>0){v.push_back(numberString);   // 考虑是多位数 numberString.erase();   // 清空erase }if(!isspace(expression[i]))   // 不是数字,则一定是运算符或者括号{ string s;s.append(1, expression[i]);v.push_back(s); } }}//结束的时候碰到数字if(numberString.size()>0)v.push_back(numberString);return v;
}// define evualation function
int evaluateExpression(const string& expression)
{Stack_improve<int> operand_stack;  // 存储操作数 Stack_improve<char> operator_stack;  // 存储运算符vector<string> token = split(expression);// phase1 scan the token  遍历分割后的表达式for(int i=0; i<token.size(); i++){if(token[i][0]=='+' || token[i][0]=='-')  // +-运算符{while(!operator_stack.isEmpty()&&(operator_stack.peek()=='+' || operator_stack.peek()=='-' || operator_stack.peek()=='*' || operator_stack.peek()=='/')){processAnOperator(operand_stack, operator_stack);               } operator_stack.push(token[i][0]);}  else if(token[i][0]=='*' || token[i][0]=='/'){// process * /while(!operator_stack.isEmpty() && (operator_stack.peek()=='*' || operator_stack.peek()=='/'))    {processAnOperator(operand_stack, operator_stack);      }operand_stack.push(token[i][0]);}else if(token[i][0]=='('){operator_stack.push(token[i][0]);}else if(token[i][0]==')'){while(operator_stack.peek()!='('){processAnOperator(operand_stack, operator_stack); }operator_stack.pop();    // pop '(' out of the stack }else{operand_stack.push(atoi(token[i].c_str()));    }}while(!operator_stack.isEmpty()){processAnOperator(operand_stack, operator_stack); }return operand_stack.pop();
} // process operator: take a operator from the operatorStack and
// apply it on the operands in the operands
void processAnOperator(Stack_improve<int> operandStack, Stack_improve<char> operatorStack)
{char op = operatorStack.pop();int op1 = operandStack.pop();int op2 = operandStack.pop();if(op=='+')operandStack.push(op1+op2);else if(op=='-')operandStack.push(op1-op2);else if(op=='*')operandStack.push(op1*op2);elseoperandStack.push(op1/op2);
}

C++笔记(9) 模板,向量和栈相关推荐

  1. Python-OpenCV 笔记9 -- 模板匹配

    Python-OpenCV 笔记9 – 模板匹配 1.模板匹配:matchTemplate() 函数原型: matchTemplate(image, templ, method[, result[, ...

  2. Django 笔记4 -- 模板

    Django 笔记4 – 模板 Django 系列笔记是笔者学习.实践使用 Django 的相关笔记,大量参考了知了课堂的<Django零基础到项目实战>教程. 参考文档: Django官 ...

  3. C++ template类模板实现栈 pop push

    心得 data = new T[size];这句太坑了,一开始写成了data = new T(size)圆括号,所以一直随机性报错. 我本来以为是ide的问题,在vs2017里就会崩,在dev里不会崩 ...

  4. 模板实现栈队列以及链表

    模板实现链表 //test.h #include <iostream> #include <cstdio> #include <assert.h> using na ...

  5. 【汇编语言与计算机系统结构笔记09】程序栈,(x86-32)过程调用,栈帧,寄存器使用惯例

    本次笔记内容: 10.栈与过程调用的机器表示-1 11.栈与过程调用的机器表示-2 12.实验 文章目录 前言 x86-32的程序栈 压栈操作 出栈操作 过程调用 基于栈的编程语言 栈帧 x86-32 ...

  6. 高效能沟《关键对话》读书笔记PPT模板-优页文档

    模板介绍 高效能沟<关键对话>读书笔记PPT模板-优页文档.一套,教育培训,读书笔记,幻灯片模板,内含青色多种配色,风格设计,动态播放效果,精美实用. 希望下面这份精美的PPT模板能给你带 ...

  7. OpenCV 学习笔记(模板匹配)

    OpenCV 学习笔记(模板匹配) 模板匹配是在一幅图像中寻找一个特定目标的方法之一.这种方法的原理非常简单,遍历图像中的每一个可能的位置,比较各处与模板是否"相似",当相似度足够 ...

  8. 《高效能人士的7个习惯》读书笔记PPT模板

    模板介绍 <高效能人士的7个习惯>读书笔记PPT模板.一套读书笔记幻灯片模板,内含橙色多种配色,风格设计,动态播放效果,精美实用. 希望下面这份精美的PPT模板能给你带来帮助,温馨提示:本 ...

  9. 《照着做,你就是最能干的人》读书笔记PPT模板

    模板介绍 <照着做,你就是最能干的人>读书笔记PPT模板.一套读书笔记幻灯片模板,内含蓝色多种配色,风格设计,动态播放效果,精美实用. 希望下面这份精美的PPT模板能给你带来帮助,温馨提示 ...

  10. 《罗辑思维》读书笔记PPT模板

    模板介绍 <罗辑思维>读书笔记PPT模板.一套读书笔记幻灯片模板,内含橙色多种配色,风格设计,动态播放效果,精美实用. 希望下面这份精美的PPT模板能给你带来帮助,温馨提示:本资源使用PP ...

最新文章

  1. 【笔记】与Android选项卡一周
  2. 2017年前端工作小结,个人踩坑之旅,前端学习者的杂谈
  3. 【Prometheus】存储
  4. Asp.net(C#)-显示所有缓存 清除所有缓存
  5. 研究人员发现:基于文本的AI模型容易受到改述攻击
  6. 深刻理解 React (一) ——JSX和虚拟DOM
  7. 微信小程序开发的坑---新建页面or修改app.json
  8. ModelAndView简介
  9. [置顶] NYOJ117 求逆序数
  10. ue4文档接口类学习
  11. html5 斗鱼 苹果,斗鱼ios端手游直播方法
  12. 花了两万块参加培训,简历投了1000多份,两个月了还是没找到工作
  13. CSS3的box-sizing 属性
  14. 量化java_用java做量化
  15. led动态显示 c语言,单片机LED点阵的横向移动(动态显示)
  16. linux内存条故障,linux – 如何从MCE消息中找到故障内存模块?
  17. 1.0、Python概述
  18. R语言计算时间序列数据的移动平均值(滚动平均值、例如5日均线、10日均线等):使用zoo包中的rollmean函数计算k个周期移动平均值
  19. 计算机能力挑战2021,2021WER能力挑战赛——“人工智能”竞赛规则.docx
  20. oracle lag使用情景,lag函数用法

热门文章

  1. NVIDIA/Apex安装时遇到 C++编译:unrecognized command line option ‘-std=c++14’ 错误解决
  2. detectron2 demo cuda10.0 py3.6
  3. 给定单链表,检测是否有环等系列考题
  4. 划分字母区间c语言,LeetCode(#763):划分字母区间
  5. 未来计算机对世界的改变,到2030年,世界将会发生的10个改变,科学家:科技决定未来!...
  6. 查询limit_MySQL查询语句(where,group by,having,order by,limit)
  7. redis aof 备份和恢复_深入理解Redis持久化
  8. python中oxf2是多少_python 函数基础2
  9. excel表头_「Excel技巧」关于Excel表格打印常见的四个问题,你会解决吗?
  10. oracle11g临时表,oracle11G的临时表空间