小学生学C++编程语法知识(C++模板(Template)详解)
C++模板(Template)详解——给小学生的“魔法公式”
同学们,今天我们学习一个在C++编程、STL标准库、算法竞赛中非常重要的知识:模板(Template)。
你平时写代码,会经常看到:
vector<int> a; sort(a.begin(),a.end());或者:
pair<int,int> p;甚至:
priority_queue<int> q;这里面的:
<int>其实就是模板参数。
那么:
为什么一个vector既可以装int,又可以装string?
为什么sort既可以排序整数,又可以排序字符串?
C++到底是怎么做到的?
这就是今天要解决的问题。
一、为什么需要模板?
1. 一个现实问题
假设我们要写一个交换两个数字的函数。
比如:
交换两个整数:
void swap(int &a,int &b) { int t=a; a=b; b=t; }使用:
int x=10; int y=20; swap(x,y);很好。
但是后来我们想交换:
double类型
double a=1.2; double b=3.5;怎么办?
重新写:
void swap(double &a,double &b) { double t=a; a=b; b=t; }发现:
代码完全一样!
区别只有:
int换成:
double后来还有:
string char long long是不是每一种都写一个?
太麻烦了。
二、模板的思想:写一个万能版本
程序员想:
能不能先不告诉计算机是什么类型?
比如:
"以后你告诉我交换什么,我自动生成对应代码。"
于是出现:
函数模板
写法:
template<typename T> void mySwap(T &a,T &b) { T temp=a; a=b; b=temp; }这里:
T就是一个占位符。
你可以理解成:
一个空盒子。
现在:
T还不知道是什么。
调用:
情况1:交换int
int a=10; int b=20; mySwap(a,b);编译器发现:
a,b是int。
于是:
把模板变成:
void mySwap(int &a,int &b) { int temp=a; a=b; b=temp; }情况2:交换double
double x=1.1; double y=2.2; mySwap(x,y);编译器生成:
void mySwap(double &a,double &b) { double temp=a; a=b; b=temp; }所以:
一个模板:
template<typename T>可以生成很多函数。
三、模板底层到底如何实现?
这是重点。
很多初学者认为:
模板是不是运行的时候判断类型?
不是!
C++模板:
不是运行时技术
而是:
编译时期生成代码
也叫:
模板实例化(Template Instantiation)
例如:
我们写:
template<typename T> T add(T a,T b) { return a+b; }调用:
cout<<add(3,5); cout<<add(1.5,2.5);编译器看到以后:
偷偷生成两个函数:
第一个:
int add(int a,int b) { return a+b; }第二个:
double add(double a,double b) { return a+b; }最后真正运行的时候:
程序里面根本没有模板!
只有:
add(int)和:
add(double)可以画成:
模板代码 template<T> | | ↓ 编译器加工 | ---------------------- | | int版本 double版本 | ↓ 最终机器代码四、为什么模板运行速度快?
因为:
模板是在编译阶段展开。
运行时:
没有:
判断类型 if(int) else(double)所以:
速度和普通函数一样。
例如:
vector
实际上:
编译器生成:
整数数组管理代码vector
生成:
double数组管理代码没有额外损耗。
五、类模板
除了函数可以模板化。
类也可以。
例如:
我们想写一个盒子。
普通类:
class Box { public: int value; };只能装:
int
如果想装:
double string怎么办?
使用:
类模板
template<typename T> class Box { public: T value; };现在:
Box<int> a; Box<double> b; Box<string> c;三个盒子:
分别变成:
Box<int> Box<double> Box<string>六、STL为什么全部使用模板?
这是竞赛中重要的地方。
1. vector
你写:
vector<int> a;实际上:
vector是模板:
template<typename T> class vector { T *data; };所以:
vector<int>变成:
整数数组管理器如果:
vector<string>变成:
字符串数组管理器七、sort为什么可以排序各种类型?
你有没有想过:
sort(a,a+n);为什么:
int可以:
5 2 9 1string也可以:
apple banana cat因为:
sort也是模板。
类似:
template<class Iterator> void sort(Iterator begin,Iterator end) { }编译器根据你的数据:
自动生成:
整数排序版本。
字符串排序版本。
八、typename 和 class 有什么区别?
经常看到:
template<typename T>也看到:
template<class T>其实这里:
没有区别。
例如:
template<class T> void fun(T x) { }等价:
template<typename T> void fun(T x) { }只是:
现代C++更推荐:
typename因为:
更能表达:
"这里是一个类型"
九、模板和普通函数有什么区别?
比较一下:
普通函数
int max(int a,int b) { return a>b?a:b; }只能:
int
模板:
template<typename T> T myMax(T a,T b) { return a>b?a:b; }可以:
myMax(3,5); myMax(2.5,8.1); myMax('a','z');十、模板的缺点
模板很强,但是也有问题。
1. 编译时间变长
因为:
一个模板可能生成很多代码。
例如:
vector<int> vector<double> vector<string> vector<long long>编译器都要生成。
2. 错误信息很复杂
例如:
模板错误:
可能出现:
几十行报错。
初学者看到:
std::__cxx11...很害怕。
其实:
通常只是:
类型不匹配。
十一、信奥竞赛中什么时候需要模板?
小学阶段:
理解:
⭐⭐⭐⭐
使用:
⭐⭐
中学竞赛:
大量使用。
例如:
STL
vector queue stack set map priority_queue sort全部依赖模板。
十二、给同学们的总结
模板是什么?
一句话:
模板就是“代码的万能设计图”。
比如:
普通代码:
一个盒子 只能装苹果模板:
一个魔法盒子 你放苹果 它变苹果盒 你放香蕉 它变香蕉盒模板底层原理:
记住一句:
C++模板不是运行时变化,而是在编译时复制生成不同版本代码。
过程:
模板 ↓ 编译器看到使用方式 ↓ 自动生成对应代码 ↓ 编译成机器语言 ↓ 运行以后学习:
vector set map priority_queue sort不要认为:
"这是C++给我的工具"
而要知道:
它们背后都是:
高级程序员利用模板技术,把通用算法提前设计好,然后让编译器自动生成适合你的版本。
这也是C++相比很多语言强大的核心原因之一。你学习模板,本质是在学习:
如何写出“一个代码,适应无限场景”的能力。
