【C++】模板入门
本篇博客给大家带来的是C++的模板入门详解!
🐟🐟文章专栏:C++
🚀🚀若有问题评论区下讨论,我会及时回答
❤❤欢迎大家点赞、收藏、分享!
一、泛型编程
代码示例:
void swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}void swap(double& x, double& y)
{double tmp = x;x = y;y = tmp;
}void swap(long& x, long& y)
{long tmp = x;x = y;y = tmp;
}
注意:由于交换数据的类型不同我们要写多个交换函数,带来的问题:代码复用率低,可维护性差,这时候我们提出了泛型编程。
泛型编程:编写与代码无关的通用代码,是代码复用的一种手段。模板是泛型编程的基础。
模板:跟古代的印刷术差不多,模板分为:函数模板和类模板。
二、函数模板
函数模板:函数模板代表这一个函数家族,该函数和类型无关,在使用时被参数化,根据实参类型来产生函数的特定类型版本。
1)书写方式:template<typename T,typename T2,。。。。,typename Tn>
返回类型:函数名(参数列表){}
代码示例:
template<class T>//typename T这样也行,不能:struct T
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}int main()
{int a = 19;int b = 32;Swap(a, b);cout <<"a:"<< a <<' ' << "b:" << b;cout << endl;double c = 7;double d = 8;cout << "c:" << c <<" " << "d:" << d;cout << endl;return 0;
}
运行结果:
注意:在上面的代码中调用的是不同的函数,调用的是同一个模板,如:
调用Swap(a,b),模板会推演实例化出一个函数:
void swap(int& x, int& y)
{int tmp = x;x = y;y = tmp;
}
调用Swap(c,d)也是一样:
void swap(double& x, double& y)
{double tmp = x;x = y;y = tmp;
}
模板的本质:我们本来要做的事交给编译器来做。
注意:实参参数不同,这时候会产生歧义,编译不通过,如:
template<class T>
void Swap(T& x, T& y)
{T tmp = x;x = y;y = tmp;
}int main()
{int a = 19;int b = 32;Swap(a, b);cout <<"a:"<< a <<' ' << "b:" << b;cout << endl;double c = 7;double d = 8;cout << "c:" << c <<" " << "d:" << d;cout << endl;Swap(a, c);//a是int类型,c是double类型,模板推演产生歧义return 0;
}
2)隐式实例化和显示实例化:
代码示例:
template<class T>
T Add(const T& x, const T& y)
{return x + y;
}int main()
{int a = 19;int b = 32;double c = 7;double d = 8;cout << Add(a, b) << endl;//隐式实例化cout << Add(a, (int)c) << endl;cout << Add<int>(a, b) << endl;//显示实例化cout << Add<int>(a, (int)c);return 0;
}
显示实例化的使用场景:
template<class T>
T* Fun(int n)
{T* ptr = new T[n];return ptr;
}int main()
{cout << Fun(10) << endl;//10传给了n,T是什么类型不知道,所以无法推演;正确写法:Fun<int>(10)告诉编译器T是int类型的return 0;
}
3)模板参数的匹配原则
原则1:
代码示例1:
template<class T>
T Add(const T& x, const T& y)
{return x + y;
}int Add(int x, int y)
{return x + y;
}int main()
{Add(1, 2);//能不模板推演就不推演,直接调用我们自己写的Add函数return 0;
}
如果非要让模板来推演可以显示实例化来调用:
template<class T>
T Add(const T& x, const T& y)
{return x + y;
}int Add(int x, int y)
{return x + y;
}int main()
{Add(1, 2);//能不模板推演就不推演,直接调用我们自己写的Add函数Add<int>(1, 2);//调用模板return 0;
}
原则2:
代码示例2:
template<class T>
T Add(const T& x, const T& y)
{return x + y;
}int Add(int x, int y)
{return x + y;
}int main()
{Add(1, 1.1);//调用更匹配的,调用我们自己写的Add函数Add<int>(1, 1.1);//强行调用模板//显示实例化return 0;
}
三、类模板
1、定义格式/书写方式
template<class T1,class T2....class Tn>
class+类模板名
{//类成员定义
};
2、类模板的实例化
代码示例:
template<class T>
class Stack
{
public:Stack(int n=4){_a = new T[n];_top = _capaciyt = 0;}void Push(const T& x){}const T& Top(){return _a[_top - 1];}
private:T* _a;size_t _top;size_t _capacity;
};int main()
{Stack<int> s1;//解决C语言只能存储指定类型的数据Stack<double> s2;//类模板只能显示实例化return 0;
}
3、类模板的声明和定义分离
代码示例:
template<class T>
class Stack
{
public:Stack(int n=4){_a = new T[n];_top = _capaciyt = 0;}void Push(const T& x);const T& Top(){return _a[_top - 1];}
private:T* _a;size_t _top;size_t _capacity;
};//声明和定义分离不建议到两个文件,处理起来麻烦
//所以一般写到同一个文件,如:
template<class T>//分离也要声明下面这行代码是类模板
void Stack<T>::Push(const T& x);int main()
{Stack<int> s1;//解决C语言只能存储指定类型的数据Stack<double> s2;//类模板只能显示实例化,Stack是类名,Stack<double>是类型return 0;
}
完!