文章目录
- 1.类模板
- 2.非类型模板参数
1.类模板
- 类模板:将类定义中的数据类型参数化,用参数来传递
eg:vector,表示vector内部所存放的数据类型是int,以此类推,vector - 类模板实际上是函数模板的推广,可以用相同的类模板来组建任意类型的对象集合
eg:vector,int类型对象的集合vector,vector,字符串类型的集合string - 类模板的定义
直接用代码说话!
template <类型形参表>
class <类名>
{ //类说明体 };
template <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数1>(形参表)
{ //成员函数定义体 }
template <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数2>(形参表)
{ //成员函数定义体 }
…
template <类型形参表>
<返回类型> <类名> <类型名表>::<成员函数n>(形参表)
{ //成员函数定义体 }
- 使用类模板
(1)类模板的实例化:用具体的数据类型替换模板的参数以得到具体的类(模板类)
(2)模板类也可以实例化为对象
(3)用下列方式创建类模板的实例:
类名 <类型实参表> 对象名称;
类模板不是类,首先要实例化出模板类,好像是函数模板,它不是函数,要先实例化出模板函数出来,才能出来。
与函数模板不同,类模板只能显式实例化为模板类,函数模板可以根据所传送的数据类型不同来自动推导,而类模板只能显式实例化
- eg:用连续的内存空间实现栈,并以模板的实现提供,这样栈可以存放任意类型
P69\Stack.h
#ifndef _STACK_H
#define _STACK_H
#include <exception>
//Stack是一个模板,并不是一个类
//typename T:将类型作为参数来传递,typename T是类型参数
template <typename T>
class Stack
{
public:
//分配一个T类型的连续内存空间
explicit Stack(int maxsize);
~Stack();
void Push(const T& elem);
void Pop();
T& Top();//返回栈顶元素,不带const说明可以改变栈内部的数据
const T& Top() const;//返回栈顶元素,带const说明不能改变栈内部的数据
bool Empty() const;//说明栈是否是空的
private:
T* elems_;
int maxSize_;
int top_;//当前的栈顶位置
};
//类的实现可以放在类说明的外部
//每个成员函数看成是一个函数模板
//Stack<T>表示模板,Stack是成员函数
template <typename T>
Stack<T>::Stack(int maxsize) : maxSize_(maxsize), top_(-1)
{
elems_ = new T[maxsize];
}
template <typename T>
Stack<T>::~Stack()
{
delete[] elems_;
}
template <typename T>
void Stack<T>::Push(const T& elem)
{
//top+1才是是元素的个数
if (top +1 >= maxSize_)
throw out_of_range(“Stack<>::Push() stack full”);//out_of_range是标准库的异常
elems_[top_++] = elem;
}
template <typename T>
void Stack<T>::Pop(const T& elem)
{
//top+1才是是元素的个数
if (top +1 == 0)
throw out_of_range(“Stack<>::Pop() stack empty”);//out_of_range是标准库的异常
--top_;
}
template <typename T>
T& Stack<T>::Top()
{
//top+1才是是元素的个数
if (top +1 == 0)
throw out_of_range(“Stack<>::Top() stack empty”);//out_of_range是标准库的异常
return elems_[top_];
}
template <typename T>
const T& Stack<T>::Top() const
{
//top+1才是是元素的个数
if (top +1 == 0)
throw out_of_range(“Stack<>::Top() const stack empty”);//out_of_range是标准库的异常
return elems_[top_];
}
template <typename T>
bool Stack<T>::Empty() const
{
return top_ + 1 == 0;
}
#endif //_STACK_H
P69\01.cpp
#include "Stack.h"
int main(void)
{
//显示的实例化一个int类型的模板类,而不是自动推导的
//Stack是一个模板,Stack<int>是一个模板类
Stack<int> s(10);//当我们使用时,Stack<int>进行实例化,是在编译器完成的,会将头文件里面的template
//那些东西用int类型来替换,模板实际上是宏和重载的结合,只是说重载的版本是编译器维护的,而不是程序员
s.Push(1);
s.Push(2);
s.Push(3);
while (!s.Empty())
{
cout<<s.Top()<<endl;
s.Pop();
}
return 0;
}
- 测试:
2.非类型模板参数
- 对于函数模板与类模板,模板参数并不局限于类型,普通值也可以作为模板参数
将值作为模板的参数也是可以的 - eg:
P69\Stack2.h
#ifndef _STACK2_H
#define _STACK2_H
#include <exception>
//Stack2是一个模板,并不是一个类
//typename T:将类型作为参数来传递,typename T是类型参数,int MAX_SIZE是非类型参数
template <typename T, int MAX_SIZE>
class Stack2
{
public:
//分配一个T类型的连续内存空间
Stack2();
~Stack2();
void Push(const T& elem);
void Pop();
T& Top();//返回栈顶元素,不带const说明可以改变栈内部的数据
const T& Top() const;//返回栈顶元素,带const说明不能改变栈内部的数据
bool Empty() const;//说明栈是否是空的
private:
T* elems_;
// int maxSize_;
int top_;//当前的栈顶位置
};
//类的实现可以放在类说明的外部
//每个成员函数看成是一个函数模板
//Stack2<T, int MAX_SIZE>表示模板,Stack2是成员函数
template <typename T, int MAX_SIZE>
Stack2<T, int MAX_SIZE>::Stack2() : top_(-1)
{
elems_ = new T[MAX_SIZE];
}
template <typename T, int MAX_SIZE>
Stack2<T, int MAX_SIZE>::~Stack2()
{
delete[] elems_;
}
template <typename T, int MAX_SIZE>
void Stack2<T, int MAX_SIZE>::Push(const T& elem)
{
//top+1才是是元素的个数
if (top +1 >= MAX_SIZE)
throw out_of_range(“Stack2<>::Push() stack full”);//out_of_range是标准库的异常
elems_[top_++] = elem;
}
template <typename T, int MAX_SIZE>
void Stack2<T, int MAX_SIZE>::Pop(const T& elem)
{
//top+1才是是元素的个数
if (top +1 == 0)
throw out_of_range(“Stack2<>::Pop() stack empty”);//out_of_range是标准库的异常
--top_;
}
template <typename T, int MAX_SIZE>
T& Stack2<T, int MAX_SIZE>::Top()
{
//top+1才是是元素的个数
if (top +1 == 0)
throw out_of_range(“Stack2<>::Top() stack empty”);//out_of_range是标准库的异常
return elems_[top_];
}
template <typename T, int MAX_SIZE>
const T& Stack2<T, int MAX_SIZE>::Top() const
{
//top+1才是是元素的个数
if (top +1 == 0)
throw out_of_range(“Stack2<>::Top() const stack empty”);//out_of_range是标准库的异常
return elems_[top_];
}
template <typename T, int MAX_SIZE>
bool Stack2<T, int MAX_SIZE>::Empty() const
{
return top_ + 1 == 0;
}
#endif //_STACK2_H
P69\02.cpp
#include "Stack2.h"
int main(void)
{
//显示的实例化一个int类型的模板类,而不是自动推导的
//Stack是一个模板,Stack<int>是一个模板类
Stack2<int, 10> s;//当我们使用时,Stack<int>进行实例化,是在编译器完成的,会将头文件里面的template
//那些东西用int类型来替换,模板实际上是宏和重载的结合,只是说重载的版本是编译器维护的,而不是程序员
s.Push(1);
s.Push(2);
s.Push(3);
while (!s.Empty())
{
cout<<s.Top()<<endl;
s.Pop();
}
return 0;
}
- 测试:
- 进一步:C++非类型模板参数