函数模板和类模板的理解
Qingyh Lv3

在C++语言中,函数声明和定义需要明确指定函数名及其参数类型,这是理解函数重载的重要概念。

函数模板

C++函数模板是一种强大的泛型编程工具,它允许我们对数据类型进行参数化,从而实现代码的高度复用。模板的核心意义在于将算法与数据类型解耦,使同一段代码可以适用于不同的数据类型

1
2
3
4
5
template<typename T>//定义一个模板参数列表
bool compare(T a,T b) //compare是一个函数模板
{
return a>b;
}

上述定义的这段代码就可以支持如int、float、double类型的数据比较。

函数模板的实例化

在函数调用点进行实例化是指在使用函数模板时,编译器会根据传入的实参在调用点自动生成对应的具体函数代码。
具体过程可以总结为:

  1. 编译器在编译时遇到函数模板调用语句
  2. 根据实参类型推导模板参数
  3. 并实例化对应类型的模板函数
  4. 编译生成的目标代码中会包含这个模板函数
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/*
实例化的int型模板函数
bool compare<int>(int a,int b)
{
return a>b;
}
实例化的double型模板函数
bool compare<double>(double a,double b)
{
return a>b;
}
*/
int main()
{
//在函数调用点,编译器根据用户指定的类型,从原模版实例化一份代码出来
//叫做模板函数
compare<int> (10,20);
compare<double>(10.5,20.5);
}

如上述代码,由于compare是函数模板,并且调用的时候分别传入了int类型的实参和double类型的实参,于是从原模板中分别实例化了int和double的模板函数。

函数模板的特例化

特例化:模板本来是一组通用逻辑的实现,但是对于某些特定的参数类型来说,通用的逻辑实现可能不能满足要求,这时就需要针对这些特殊的类型去实现一个特例模板,即模板的特例化。

函数模板特例化,是将模板参数全部指定成特定的类型(并对这个类型的逻辑进行修改),但不等价于函数重载,两者不要混淆。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/*针对compare这个模板函数,能适用于大部分数据类型,如int ,double,以及简单对象,但是也有特例
如compare("aaa","bbb"),根据函数推演,其应该是
bool <const char *>(const char *,const char *)
{
return a<b;
}
这样比较的是a和b两个地址的大小,而非字典序大小,
针对这种情况,提供const char *这个类型的特例化版本
*/
template<>
bool compare(const char *a,const char *b)
{
return strcmp(a,b)>0;
}

【深入理解C++】函数模板和类模板的特例化

非模板函数-普通函数

1
2
3
4
5
6
//template<> //没有这个template定义的就是普通函数
bool compare(const char *a,const char *b)
{
return a<b;
}

注意:模板代码是不能在一个文件中定义,在另外一个文件中使用的。模板代码调用之前,一定要看到模板定义的地方,这样模板才能够正常的实例化,产生能够被编译器编译的代码。所以,一般模板代码都是放在头文件中的。
不过如果是跨文件调用的话,在该函数模板定义的文件中,告诉编译器进行指定类型的模板实例化也是可以的(这种一般不推荐,要手动初始化多个类型的模板函数)。

类模板

类模板与函数模板的定义和使用类似,存在多个类,其功能是相同的,仅仅是数据类型不同,就可以通过类模板复用代码:

1
2
template    <类型形式参数表>
类声明

以下是基于类模板模拟实现了一个栈,支持入栈、出栈、判断栈满、判断栈空、查看栈顶原始,扩容;实现了支持深拷贝的拷贝构造函数和赋值构造函数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
template <typename T>
class SeqStack //模板名称+类型参数列表=类名称
{
public:
//构造和析构函数不用加<T>(在类里面,就是类模板)
//但是其他出现模板的地方都加上类型参数列表
SeqStack(int size=10)
:_pstack(new T[size])
,_top(0)
,_size(size)
{}

~SeqStack()
{
delete []_stack;
_pstack=nullptr;
}

SeqStack(const SeqStack<T> &stack) //重载拷贝构造运算符
:_top(stack._top)
,_size(stack._size)
{
_pstack=new T[_size];
//memcopy是浅拷贝,一般仅用于一些内置类型,对于对象等一般for循环赋值
for (int i=0;i<_top;++i)
{
_pstack[i]=stack._pstack[i];
}
}
SeqStack<T> &operator=(const SeqStack<T> &stack) //重载赋值运算符
{
if (this==&stack) //防止自赋值,
return *this;

delete []_pstack;//删除其指向的原有数据堆
_top=stack._top;
_size=stack._size;

//这部分跟拷贝构造执行的一样
_pstack=new T[_size];
for (int i=0;i<_top;++i)
{
_pstack[i]=stack._pstack[i];
}
return *this;
}

void push(const T &val) //入栈操作
{
if (full())
expand();
_pstack[_top++]=val;
}
void pop()
{
if(empty())
return;
--top;
}
T top() const
{
if (empty())
throw "stack is empty"; //抛出异常
return _pstack[_top-1];
}

bool full() const {return _top==_size;}
bool empty() const {return _top==0; }
private:
T *_pstack; //这个指向了外部资源,堆区,要使用深拷贝
int _top;
int _size;

//顺序栈底层数组按2倍方式扩容
void expand()
{
T *ptmp=new T[_size*2];
for (int i=0;i<_top;++i)
{
ptmp[i]=_pstack[i];
}
delete []_pstack;
_pstack=ptmp;
_size*=2;
}

}

C++ 类模板(template)详解

$share-item-width = 1.8rem .post-share-container { flex-shrink 0 .share-list-wrap { display flex justify-content flex-end .share-item { width $share-item-width height $share-item-width margin-left 0.5rem padding 0.4rem border-style solid border-width 0.1rem border-radius 50% cursor pointer transition-t("background", "0", "0.3", "ease") i { color inherit font-size 1rem } &.qq { color var(--keep-primary-color) border-color var(--keep-primary-color) &:hover { color var(--background-color-1) background var(--keep-primary-color) } } &.wechat { color var(--keep-success-color) border-color var(--keep-success-color) img { filter brightness(1) !important &[lazyload] { &::before { background #fff !important } } } &:hover { color var(--background-color-1) background var(--keep-success-color) } } &.weibo { color var(--keep-danger-color) border-color var(--keep-danger-color) &:hover { color var(--background-color-1) background var(--keep-danger-color) } } } } }
if (hexo-config('comment') && hexo-config('comment.enable') == true && hexo-config('comment.use')) { if (hexo-config('comment.use') == "valine") { @import "./valine.styl" } else if (hexo-config('comment.use') == "gitalk") { @import "./gitalk.styl" } else if (hexo-config('comment.use') == "twikoo") { @import "./twikoo.styl" } else if (hexo-config('comment.use') == "waline") { @import "./waline.styl" } } .comments-container { display inline-block width 100% margin-top var(--component-gap) .comment-area-title { width 100% color var(--text-color-3) font-size 1.38rem line-height 2 i { color var(--text-color-3) } +keep-tablet() { font-size 1.2rem } } .configuration-items-error-tip { display flex align-items center margin-top 1rem color var(--text-color-3) font-size 1rem i { margin-right 0.3rem color var(--text-color-3) font-size 1.2rem } } .comment-plugin-fail { display none flex-direction column align-items center justify-content space-around width 100% padding 2rem .fail-tip { color var(--text-color-3) font-size 1.1rem } .reload { margin-top 1rem } } .comment-plugin-loading { flex-direction column padding 1rem color var(--text-color-3) .loading-icon { color var(--text-color-4) font-size 2rem } .load-tip { margin-top 1rem color var(--text-color-4) font-size 1.1rem } } }
由 Hexo 驱动 & 主题 Keep
本站由 提供部署服务
总字数 42.9k
$li-margin-bottom = 0.8rem $post-tool-button-width = 2.5rem .post-tools-container { padding-top var(--component-gap) .post-tools-list { li { margin-bottom $li-margin-bottom &:last-child { margin-bottom 0 } } li.tools-item { position relative box-sizing border-box width $post-tool-button-width height $post-tool-button-width color var(--text-color-3) font-size 1.2rem background var(--background-color-1) border-radius 50% box-shadow 2px 2px 5px var(--shadow-color) cursor pointer &:hover { box-shadow 2px 2px 8px var(--shadow-hover-color) } i { color var(--text-color-3) } &:hover { color var(--background-color-1) background var(--primary-color) i { color var(--background-color-1) !important } } &.toggle-show-toc { display none } &.go-to-comments { .post-comments-count { position absolute top 0 right -1rem display none align-items center justify-content center box-sizing border-box min-width 1.1rem height 1.1rem padding 0 0.2rem color var(--badge-color) font-size 12px background var(--badge-background-color) border-radius 0.4rem +keep-tablet() { display none !important } } } } li.status-item { width $post-tool-button-width height $post-tool-button-width color var(--text-color-3) font-size 1.6rem cursor pointer &.post-lock { cursor default .fa-lock-open { display none color var(--keep-success-color) } &.decrypt { cursor pointer .fa-lock-open { display block } .fa-lock { display none } } } } } }