1.泛型编程

为了引入这个泛型编程,我们先来思考一个问题:如何写出一个通用的交换函数呢,所谓的通用,就是指可以交换整型,浮点型,字符型,以及自 定义 类型呢?

如果我们还没有学C++,那么我们可能Ctrl+C、Ctrl+V去创建很多个函数,但是C++提供了一个很好用的方式,就是给编译器生成一个模子,让编译器根据不同的 类 型来生成不同的函数,即使是自定类型也可以


2.函数模版

2.1函数模版的定义

函数模版在 使用 时里面的类型被实例化,生成特定类型的函数版本

2.2函数模版的格式

template / template

返回值类型 函数名 (参数列表)

{

}

2.3函数模版的 原理

函数模版就是给编译器提供一个模子,蛋挞本省不是函数,在调用他的时候,会生成具体类型的函数版本。所以就是编译器帮我们做了很多没有用并且重复度的工作。在编译阶段,编译器会根据实参的类型推演生成对应类型的函数。

2.4函数模版的 实例 化

使用不同类型的参数调用函数模版时,叫做函数模版的实例化,函数模版的实例化分为显示实例化和隐式实例化。

1.隐式实例化。让编译器根据实参来自动推演模版参数的实际类型

1
2
3
4
5
6
7
8
9
10
11
template<typename T>
T add(const T& a,const T& b)
{
return (a + b);
}
int main()
{
int a = 10, b = 20;
cout << add(a, b) << endl;
return 0;
}

可以看到我们在调用的时候没有传入T的类型,但是编译器会自动识别并生成对应函数

但是还有其它的情况

1
2
3
4
5
6
7
8
9
10
11
12
template<typename T>
T add(const T& a,const T& b)
{
return (a + b);
}
int main()
{
int a = 10;
double b = 20.2;
cout << add(a, b) << endl;
return 0;
}

这样的话就只能把a或者b强转成一个类型。

2.显示实例化:调用函数时,在函数名后面的<>中指定模版参数的实际类型

1
2
3
4
5
6
7
8
9
10
11
12
template<typename T>
T add(const T& a,const T& b)
{
return (a + b);
}
int main()
{
int a = 10;
double b = 20.2;
cout << add<int>(a, b) << endl;
return 0;
}

2.5模版参数的匹配原则

1.一个同名的非模板函数可以和一个同名的模板函数同时存在,而且那个模板函数还可以实例化成那个非模板函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
template<typename T>
T add(const T& a,const T& b)
{
return (a + b);
}
int add(int a, int b)
{
return (a + b);
}
int main()
{
int a1 = 9,b1 = 10;
double a2 = 20.1,b2 = 20.2;
cout << add(a2,b2) << endl;
cout << add<int>(a1,b1)<< endl;
cout << add(a1, b1) << endl;
return 0;
}

 补充:编译器的风格是

有符合要求的成品函数就调用成品函数,如果没有的话就使用模板函数。但是如果模板函数和非模板函数都能使用的时候,编译器会优先使用非模板函数。但是你也可以用函数名显示调用模板函数,这样的话,编译器就会调用模板函数而不是非模板函数

 2.模板函数不允许自动进行类型转换,但是非模板类型可以自动进行类型转换(也就是说废模板类型可以强制类型转换)

3.类模板

3.1类模板的定义格式

template

class 类名

{

        //成员函数

}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
template<typename T>
class Stack
{
public:
Stack(int n = 4)
:_array = new T[n]
, _capacity = 4
, _size = 0;
{

}
private:
T* _array;
size_t _capacity;
size_t _size;
};

注意:类模板在定义对象的时候,只能显示定义,不能让编译器自己去隐式推演 

eg:Stack s1;

        Stacks2;

3.2类模板里面成员函数的定义与声明分离

在指定类域的时候,需要类名+<模板参数>,比如:Stack

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
template<typename T>
class Stack
{
public:
Stack(int n = 4)
:_array(new T[n])
, _capacity(4)
, _size(0)
{
}
void Push(const T& x);
private:
T* _array;
size_t _capacity;
size_t _size;
};
template<typename T>
void Stack<T>::Push(const T& x)
{
_array[_size] = x;
_size++;
}