梳理STL学习过程中的笔记
学STL,首先要搞清楚什么是模板
函数模板
或者是用 <Class T>都是一样的
1 | template <typename T> |
2 | |
3 | int function(const T& a, const T& b) |
4 | |
5 | { |
6 | |
7 | ... ... |
8 | |
9 | } |
10 | |
11 | template <typename T> |
12 | |
13 | inline int function(const T& a) |
14 | |
15 | { |
16 | |
17 | ... ... |
18 | |
19 | } |
怎么使用呢?
直接填值就可以了
编译器根据值的类型进行判断,不用多操心
函数模板的实例化
1 | function(1, 2); |
2 | |
3 | CString str1, str2; |
4 | |
5 | function(str1, str2); |
推断类型的时候不带强制类型转换的 否则怎么推断呢
在模板函数内部, 是可以强制类型转换的
比如模板函数调用某个库函数的时候,传给库函数的类型不完全吻合时
PS:
VC++中有<string.h>文件,它就是C中的那个;
而<cstring>文件实际上只是在一个命名空间std中include了<string.h>,这是因为C++要减少名称污染;
类模板
和函数模板完全一样 只是实例化的时候方式不同
实例化的时候 会被强制类型转换的
1 | template <typename T> |
2 | |
3 | class Stack |
4 | |
5 | { |
6 | |
7 | push(T& a); |
8 | |
9 | ... ... |
10 | |
11 | } |
类的实例化
1 | Queue<int> qs; |
形成一个int代替形参表的类类型
并产生该类型的一个对象 qs
====================================================================
外界定义的和形参一样的 会在模板内部屏蔽掉
1 | typedef double T |
2 | |
3 | template <typename T> |
4 | |
5 | int function(T& a ) |
6 | |
7 | { |
8 | |
9 | 外界定义的T会被隐藏掉 |
10 | |
11 | } |
内部不允许再次使用形参做变量名
1 | template <typename T> |
2 | |
3 | int function(T& a ) |
4 | |
5 | { |
6 | |
7 | typedef double T; // 非法 |
8 | |
9 | } |
形参中每一种类型前面都要加typename或者class
类型的子类型
T是一个类型 SubT是T类型的子类型
什么是子类型?
就是比如T是一个类
1 | template <class T> |
2 | |
3 | class Cls |
4 | |
5 | { |
6 | |
7 | typedef int SubT; |
8 | |
9 | } |
1 | template <typename T> |
2 | |
3 | T fun(T& a) |
4 | |
5 | { |
6 | |
7 | T::SubT* p; // 系统不知道SubT是子类型 会以为是T的静态成员变量 认为是两者的乘积(T::SubT)*(p) |
8 | |
9 | } |
1 | template <typename T> |
2 | |
3 | T fun(T& a) |
4 | |
5 | { |
6 | |
7 | typename T::SubT* p; // SubT是一种类型 |
8 | |
9 | } |
1 | template <class T,class U> |
2 | |
3 | class Cls |
4 | |
5 | { |
6 | |
7 | typedef U SubT; |
8 | |
9 | } |
==========================================================
现在看看非类型模板形参是怎么回事儿
1 | #include <iostream> using namespace std; |
2 | template <class T,int N> |
3 | int getDim(const T (&a)[N]) |
4 | { |
5 | return N; |
6 | } |
7 | |
8 | int main() |
9 | { |
10 | double d[234]; |
11 | cout << getDim(d); |
12 | return 0; |
13 | } |
14 | |
15 |
由于有这样的定义
1 | const T (&a)[N] |
所以实例化的时候 &a 实例化为d N实例化为234
相当于形参表为 <double, 234>
只是传递的时候只需要传递 d 就可以了
为什么只需要传递d呢 因为d是函数getDim的参数 类型和个数都由d自己的属性来确定
数组d的类型被自动识别 把T实例化为double类型
类型为int的N被自动识别 实例化为数组d的单元数
类的等价性???
==============================================================================
数组的引用传递
1 | void print(int (&arr)[10]); // 需要指定数组长度,长度不一致将不匹配 |
2 | int main() |
3 | { |
4 | int i[2]; |
5 | int k[10]; |
6 | print(i);// error |
7 | print(k);//OK |
8 | } |
所以在模板中认为数组引用传递的时候 如果两个数组的长度不同 他们是不同的类型
1 | template <typename T> |
2 | T fref(T &, T&) |
3 | { |
4 | ... ... |
5 | } |
6 | int a[5]; |
7 | int b[10]; |
8 | fref(a, b);// error类型不同 |
更复杂一点的实例化应用是 用函数指针指向某个实例化的模板 这样模板就实例化为那个指针的类型
1 | template <typename T> |
2 | int compare(const T&, const T&); |
3 | |
4 | int (*pf)(const int&, const int&) = compare; |