在C++中,模板类是一种用于创建通用数据结构或算法的强大工具。模板类允许您编写一次代码,然后在不同数据类型上重复使用它,以提高代码的可重用性和灵活性。
模板类允许您定义一种通用的类模板,其中某些成员或函数可以根据不同数据类型进行参数化。它们使用template关键字定义
template <class T>
class 类模板名
{
类的定义;
};
函数模板建议用 typename
描述通用数据类型,类模板建议用 class
。
template<class T1, class T2>
class MyClass {
public:
T1 a_;//通用类型用于成员变量
T2 b_;
MyClass() {}
//通用类型用于成员函数的参数
MyClass(T1 a, T2 b) : a_(a), b_(b) {
}
//通用类型用于成员函数返回值
T1 fun() {
T1 a = 2; //通用类型用于成员函数代码中
return a;
}
};
int main() {
MyClass<int, double> myClass;//用模板类AA创建对象myClass,其中的数据类型只能显示设置,不能隐形自动推导
myClass.a_=30;
myClass.b_=32.9;
cout<<myClass.fun();//2
}
在创建对象的时候,必须指明具体的数据类型。
MyClass<int, double> myClass;//用模板类AA创建对象myClass,其中的数据类型必须指明,不能隐形自动推导,
使用类模板时,数据类型必须适应类模板中的代码。
template<class T1, class T2>
class MyClass {
public:
T1 a_;//通用类型用于成员变量
T2 b_;
MyClass() {}
//通用类型用于成员函数的参数
MyClass(T1 a, T2 b) : a_(a), b_(b) {
}
//通用类型用于成员函数返回值
T1 fun() {
//假如T1的类型是string字符串,那么这句话就是错的
T1 a = 2; //通用类型用于成员函数代码中
return a;
}
};
类模板可以为通用数据类型指定缺省的数据类型(C++11 标准的函数模板也可以,但是对函数模板意义不大)。
template<class T1, class T2=double>//如果第二个缺失,默认使用double
class MyClass {
public:
T1 a_;//通用类型用于成员变量
T2 b_;
MyClass() {}
//通用类型用于成员函数的参数
MyClass(T1 a, T2 b) : a_(a), b_(b) {
}
//通用类型用于成员函数返回值
T1 fun() {
T1 a = 2; //通用类型用于成员函数代码中
return a;
}
};
int main() {
MyClass<int> myClass;//缺少第二个参数,默认使用double
myClass.a_=30;
myClass.b_=32.9;
cout<<myClass.fun();//2
}
模板类的成员函数可以在类外实现。
template<class T1, class T2>
class MyClass {
public:
T1 a_;//通用类型用于成员变量
T2 b_;
MyClass() {}
//通用类型用于成员函数的参数
MyClass(T1 a, T2 b) : a_(a), b_(b) {
}
//通用类型用于成员函数返回值
T1 fun();
};
//在类外定义,但是类外不支持数据类型缺省,因为不同的编译器可能不支持
template<class T1, class T2>
T1 MyClass<T1,T2>::fun() {
T1 a = 2; //通用类型用于成员函数代码中
return a;
}
int main() {
MyClass<int,double> myClass;//用模板类AA创建对象myClass,其中的数据类型只能显示设置,不能隐形自动推导
myClass.a_=30;
myClass.b_=32.9;
cout<<myClass.fun();//2
}
可以用 new 创建模板类对象。
template<class T1, class T2>
class MyClass {
public:
T1 a_;//通用类型用于成员变量
T2 b_;
MyClass() {}
//通用类型用于成员函数的参数
MyClass(T1 a, T2 b) : a_(a), b_(b) {
}
//通用类型用于成员函数返回值
T1 fun() {
T1 a = 2; //通用类型用于成员函数代码中
return a;
}
};
int main() {
MyClass<int,double> *myClass = new MyClass<int,double>;
MyClass<int,double> *myClass1 = new MyClass<int,double>(3,1.4);
}
在程序中,模板类的成员函数使用了才会创建。
template<class T1, class T2>
class MyClass {
public:
T1 a_;//通用类型用于成员变量
T2 b_;
MyClass() {
a_.ccc;//这行会报错
}
};
int main() {
MyClass<int,int> *m;//只声明了指针,但未创建类对象,不会调用构造函数,所以不会报错
}
template<class T1, class T2>
class MyClass {
public:
T1 a_;//通用类型用于成员变量
T2 b_;
MyClass() {
}
void fun(){
a_.da2342342();
}
};
int main() {
MyClass<int,int> *m=new MyClass<int,int>;//也不会报错,因为每调用fun函数
}
普通类实现:以int
类型为例
class Stack{
private:
int *items;//栈数组
int stacksize;//栈大小
int top;//栈顶指针
public:
//构造函数
Stack(int size):stacksize(size),top(0){
items = new int[size];
}
//析构函数
~Stack(){
delete []items;//释放内存
items=nullptr;
}
//判断是否为空
bool isEmpty() const{
return top == 0;
}
//判断是否已满
bool isFull() const{
return top == stacksize;
}
//入栈
bool push(const int& item){
if(isFull()){
return false;
}
items[top++] = item;
return true;
}
//出栈
bool pop(int &item){
if(isEmpty()){
return false;
}
item = items[--top];
return true;
}
};
int main(){
Stack stack(10);
stack.push(1);
stack.push(2);
stack.push(3);
int popitem;
while (!stack.isEmpty()){
stack.pop(popitem);
cout << popitem << endl;
}
}
使用typedef来自定义元素类型,实现类似于类模板功能
typedef int DataType;//定义数据类型
class Stack{
private:
DataType *items;//栈数组
int stacksize;//栈大小
int top;//栈顶指针
public:
//构造函数
Stack(int size):stacksize(size),top(0){
items = new DataType[size];
}
//析构函数
~Stack(){
delete []items;//释放内存
items=nullptr;
}
//判断是否为空
bool isEmpty() const{
return top == 0;
}
//判断是否已满
bool isFull() const{
return top == stacksize;
}
//入栈
bool push(const DataType& item){
if(isFull()){
return false;
}
items[top++] = item;
return true;
}
//出栈
bool pop(DataType &item){
if(isEmpty()){
return false;
}
item = items[--top];
return true;
}
};
int main(){
Stack stack(10);
stack.push(1);
stack.push(2);
stack.push(3);
DataType popitem;
while (!stack.isEmpty()){
stack.pop(popitem);
cout << popitem << endl;
}
}
使用类模板实现
template<class DataType>//模板类
class Stack{
private:
DataType *items;//栈数组
int stacksize;//栈大小
int top;//栈顶指针
public:
//构造函数
Stack(int size):stacksize(size),top(0){
items = new DataType[size];
}
//析构函数
~Stack(){
delete []items;//释放内存
}
//判断是否为空
bool isEmpty() const{
return top == 0;
}
//判断是否已满
bool isFull() const{
return top == stacksize;
}
//入栈
bool push(const DataType& item){
if(isFull()){
return false;
}
items[top++] = item;
return true;
}
//出栈
bool pop(DataType &item){
if(isEmpty()){
return false;
}
item = items[--top];
return true;
}
};
int main(){
Stack<int> stack(10);
stack.push(1);
stack.push(2);
stack.push(3);
int popitem;
while (!stack.isEmpty()){
stack.pop(popitem);
cout << popitem << endl;
}
}
template <class DataType,int len>
class Array{
private:
DataType array[len];
public:
Array(){
memset(array,0,sizeof(array));
}
~Array(){}//由于没有堆空间,析构函数可以为空
//重写下标运算符,包含非const和const版本
//非const版本,可以直接修改数组元素
DataType& operator[](int index){
return array[index];
}
//const版本,不可以修改数组元素
const DataType& operator[](int index) const{
return array[index];
}
};
int main(){
Array<int,10> array;
array[0]=3;
array[1]=4;
for (int i = 0; i < 2; ++i) {
cout<<array[i]<<endl;
}
}
注意:
类模板可以有非通用类型参数:template
Array array;
Array array;
template
Array array;
template<class DataType>
class Vector {
private:
DataType *vector;
int len;
public:
Vector(int size = 2) : len(size) {
vector = new DataType[size];
}
~Vector() {
delete[] vector;
vector = nullptr;
}
//调整数组大小函数
void resize() {
DataType *new_vector = new DataType[len * 2];//重新申请一个两倍len大小的数组
for (int i = 0; i < len; ++i) {//拷贝原始数据
new_vector[i] = vector[i];
}
delete[] vector;//释放原来的数组
vector = new_vector;//让数组指针指向新数组
len = len * 2;//更新数组长度
}
//获取数组长度
int getsize() {
return len;
}
//重写下标运算符,包含非const和const版本
//非const版本,可以直接修改数组元素
DataType &operator[](int index) {
if (index >= len) {
resize();//如果要插入或修改的元素大于等于原始数组大小,则扩充数组大小
}
return vector[index];
}
//const版本,不可以修改数组元素,这里不用修改,因为是只读的
const DataType &operator[](int index) const {
return vector[index];
}
//由于可变数组类里面包含堆元素,因此要实现深拷贝,重写赋值运算符
Vector<DataType>& operator=(const Vector<DataType> &vec) {
//释放原内存
delete[] vector;
len = vec.len;
vector = new DataType[len];//重新分配数组
for (int i = 0; i < len; ++i) {
vector[i] = vec.vector[i]; //拷贝数组中的元素
}
return *this;
}
};