要想迅速掌握函数模板,需要函数模板的知识储备(传送门)
我就勉为其难,xue微花一点时间再深入讲解一下:
模板 ( template ) :
利用一种完全通用的方法来设计函数或 x类而不必预先说明将被使用的每个对象的类型,利用模板功能可以构造相关的函数或类的系列,因此模板也可称为参数化的类型。
在C++语言中,模板可分为类模板 ( class template ) 和函数模板 ( function template ) 。
区分:
函数模板和类模板:具有各种形状的模板
实际函数和模板特化: 形状相同,需要涂上不同的颜色
我又拿出了这个可爱俏皮的函数模板:
template <typename T>
T maximum(T a,T b,T c) {
T ans,t;
ans=((t=(a>b)?a:b)>c)? t:c;
return ans;
}
看到第一行:
template <typename T>
template
ORtemplate
template关键字+
模板参数列表:
- 参数称为formal type parameter ( 形式类型参数 )。
- 占位符 ( T ) , 在函数调用时替换为基本数据类型或用户自定义数据类型。
- 每个参数都必须以关键词class ( 或typename ) 起头,参数和参数之间必须以逗号分隔, 如
我们可以抽象出函数模板的大体构架:
template <类型形参表>
返回值类型 函数名(形参表)
{
函数定义体
}
注意:
- <类型形参表>可以有一到若干个形参,各形参前必须加上class关键字,表示传递类型,当有多个形参时,各形参间用逗号分隔。
- <类型形参表>中的每个形参表示一种数据类型。“形参表”中至少有一个形参的类型必须用<类型形参表>中的形参来定义 ( 简单来说,必须有一个需要用户自定义的类型 )。
- 函数模板只是说明,不能直接执行,需要特化为模板函数后才能执行。
我们需要简单了解函数模板再计算机内部的处理方式,这样有助于我们之后的学习
template
void printArray(const T *array,int count);
printArray(intArray,count);
void printArray(const int* array,int count);
template<class 类型参数> //模板声明
class 类名 // 类定义
{ ... };
template<class arg1,int arg2,class arg3>
class myclass {
arg1 buffer[arg2];
arg3 x; //类的定义体
};
template <类型形参表>
函数返回类型 类模板名<类型名表>::成员函数(形参)
注意:
- 类模板定义只是对类的描述,ta本身还不是一个实实在在的类
- 类模板不能直接使用,必须先特化为相应的模板特化,创建**特化类的对象(实例)**后,才可使用
- 可以用以下方式创建类模板的实例
类模板名<类型实参表> 对象名表
此处的<类型实参表>要与该模板中的<类型形参表>匹配,要具有同样的顺序和类型,否则会产生错误。
栈:先进后出
数据结构:
- size:栈的大小
- top: 栈顶位置,初始值为-1(空栈)
- stackPtr :存储栈中元素的一组连续存储空间
操作:- push:如果栈不满,则向栈中增加一个元素,top增1
- pop: 如果栈不空,则从栈中弹出一个元素,top减1
- isEmpty:如果top为-1,则栈为空
- isFull:如果top为size-1,则栈满
需求:建立栈的类模板,满足不同类型的元素
//Stack.h
//创建类模板Stack,包含类型参数T
#ifndef STACK_H
#define STACK_H
template<typename T> //template+模板参数列表
class Stack
{
public:
Stack(int =10); // default constructor (Stack size 10)
// destructor
~Stack() {delete [] stackPtr;}
//成员函数在参数列表中使用类型参数T
bool push(const T&); // push an element onto the Stack
bool pop(T&); // pop an element off the Stack
// determine whether Stack is empty
bool isEmpty() const {return top==-1;}
// determine whether Stack is full
bool isFull() const {return top==size-1;}
private:
int size;
int top; // location of the top element (-1 means empty)
T *stackPtr; // pointer to internal representation of the Stack
};
//在类模板的外部定义成员函数
//template<类型形参表>
//函数返回类型 类模板名<类型名表>::成员函数(形参)
template<typename T>
Stack<T>::Stack(int s):size(s>0 ? s:10),top(-1),stackPtr(new T[size]) {}
template<typename T>
bool Stack<T>::push(const T &pushValue) {
if (!isFull()) {
stackPtr[++top]=pushValue; // place item on Stack
return true; // push successful
}
return false; // push unsuccessful
}
template<typename T>
bool Stack<T>::pop(T &popValue) {
if (!isEmpty()) {
popValue=stackPtr[top--];
return true;
}
return false;
}
#endif
// Stack class template test program.
#include
#include "Stack.h" // Stack class template definition
using namespace std;
int main()
{
Stack<double> doubleStack(5);
double doubleValue=1.1;
cout<<"Pushing elements onto doubleStack\n";
while (doubleStack.push(doubleValue)) {
cout<<doubleValue<<' ';
doubleValue+=1.1;
}
cout<<"\nStack is full. Cannot push "<<doubleValue
<<"\n\nPopping elements from doubleStack\n";
while (doubleStack.pop(doubleValue))
cout<<doubleValue<<' ';
cout<<"\nStack is empty. Cannot pop\n";
Stack<int> intStack;
int intValue=1;
cout<<"\nPushing elements onto intStack\n";
while (intStack.push(intValue)) {
cout<<intValue<<' ';
intValue++;
}
cout<<"\nStack is full. Cannot push "<<intValue<<"\n\nPopping elements from intStack\n";
while (intStack.pop(intValue))
cout<<intValue<<' ';
cout<<"\nStack is empty. Cannot pop"<<endl;
return 0;
}
为了避免main函数中重复的逻辑,我们可以使用函数模板
#include
#include
#include "Stack.h"
using namespace std;
template<typename T>
void testStack(Stack<T> &theStack,T value,T increment,const string stackName) {
cout<<"\nPushing elements onto "<<stackName<<'\n';
while (theStack.push(value)) {
cout<<value<<' ';
value+=increment;
}
cout<<"\nStack is full. Cannot push "<<value<<"\n\nPopping elements from "<<stackName<<'\n';
while (theStack.pop(value))
cout<<value<<' ';
cout<<"\nStack is empty. Cannot pop"<<endl;
}
int main()
{
Stack<double> doubleStack(5);
Stack<int> intStack;
testStack(doubleStack,1.1,1.1,"doubleStack");
testStack(intStack,1,1,"intStack");
return 0;
}
康大大的blog不够香嘛~
这里老师讲的乱七八糟,实际上想说的只有一句话:
在类型形参中的普通数据类型形参,特化后就有着和常量一样的效力,可以用来直接定义数组等
举个最简单的栗子:
template <class T,int size>
class Stack {
T buffer[size];
int top;
public:
Stack() {top=-1;}
bool push(const T &x);
bool pop(T &x);
bool isEmpty() const {return top==-1;}
bool isFull() const {return top==size-1;}
};
template <class T,int size>
bool Stack<T,size>::push(const T &x) {
if (!isFull()) {
buffer[++top]=x;
return true;
}
return false;
}
template <class T,int size> bool Stack<T,size>::pop(T &x) {
if (!isEmpty()) {
x=buffer[top--];
return true;
}
return false;
}
// 特化类模板
Stack<int,100> st1;
Stack<double,200> st2;
explicit specializations(显式特化)
class Stack { … };
下面我要飞速介绍(不要求掌握的得心应手的知识点,我们就惊鸿一撇):
关于友元的介绍
一句话总结:被friend声明的内容可以在该类class大括号之外的区域,访问该类的非公有成员
template<typename T>
class X { ... };
friend void f1();
friend void f2(X &);
friend void A::f3();
friend void C::f4(X &);
friend class Y;
( 无类型参数 )friend class Z;
( 有类型参数 )类模板中重载<<和>>,也是非常重要的内容,我就不废话了直接上大神链~
其实,我觉得这才是这一章中最重要的知识点,但是疲惫的我决定直接上栗子
用Linklist ( 链表 ) 实现一个栈模板:
template<class T>
class linkedStack;
template<class T>
class Node {
friend linkedStack<T>; //友元类
private:
T data;
Node<T> *link;
};
template<class T>
class linkedStack //栈模板定义
{
friend ostream& operator<<(ostream &out,linkedStack<T> &s) {
T elem;
while (!s.IsEmpty()) {
s.Delete(elem);
out<<elem<<endl;
}
return out;
}
public:
linkedStack() {top=0;}
~linkedStack();
bool IsEmpty() const {return top==NULL;}
bool IsFull() const;
linkedStack<T> &Add(const T&x);
linkedStack<T> &Delete(T &x);
private:
Node<T> *top;
};
template<class T>
linkedStack<T>::~linkedStack() {
Node<T> *next;
while (top!=0) {
next=top->link;
delete top;
top=next;
}
}
template<class T>
bool linkedStack<T>::IsFull() const {
try {
Node<T> *p=new Node<T>;
delete p;
return false;
}
catch (...) {return true;}
}
template<class T>
linkedStack<T> & linkedStack<T>::Add(const T &x) {
Node<T> *p=new Node<T>;
p->data=x;
p->link=top;
top=p;
return *this;
}
template<class T>
linkedStack<T> & linkedStack<T>::Delete(T &x) {
Node<T> *temp=NULL;
x=top->data;
temp=top->link;
delete top;
top=temp;
return *this;
}
int main()
{
linkedStack<int> l;
for (int i=0;i<=10;i++) {
l.Add(i*10);
}
cout<<l;
return 0;
}
最后我们xue微来了解一下:
从类模板实例化的每个模板特化有自己的static数 据成员
template <class T>
class A {
static int x;
};
Template <class T> int A<T>::x=0;
A<int> a1,a2; // a1和a2共享一个x
A<double> b1,b2; // b1和b2共享一个x