博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ Template 基础篇(二):类模板
阅读量:4178 次
发布时间:2019-05-26

本文共 4715 字,大约阅读时间需要 15 分钟。

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/lezardfu/article/details/57416241

Template 基础篇-类模板

Template所代表的泛型编程是C++语言中的重要的组成部分,我将通过几篇blog对这半年以来的学习做一个系统的总结,本文是基础篇的第二部分。

类模板定义

类模板也是公共逻辑的抽象,通常用来作为容器(例如:vector)或者行为(例如:clonable)的封装。

类模板

下面定义了一个Printer类模板,负责打印以及转化为string。

template
class Printer {public: explicit Printer(const T& param):t(param){} string&& to_string(); //定义在内部 void print() { cout << t << endl; }private: T t;};//定义在外部template
string&& Printer
::to_string() { strstream ss; ss << t; return std::move(string(ss.str()));}Printer p(1); //errorPrinter
p(1); //ok
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23

与函数模板不同,类模板不能推断实例化。所以你只能显示指定类型参数使用Printer<int> p(1),而不能让编译器自行推断Printer p(1)

类模板的成员函数既可以定义在内部,也可以定义在外部。定义在内部的被隐式声明为inline,定义在外部的类名之前必须加上template的相关声明。

类模板中的成员函数模板

我们还可以把类模板和函数模板结合起来,定义一个含有成员函数模板的类模板。

template
class Printer {public: explicit Printer(const T& param):t(param){} //成员函数模板 template
void add_and_print(const U& u);private: T t;};//注意这里要有两层template的说明template
template
void Printer
::add_and_print(const U& u) { cout << t + u << endl;}Printer
p(42);p.add_and_print(1.1); //自动推断U为double,打印出43.1 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20

类模板Tips

类模板中的static成员

类模板中可以声明static成员,在类外定义的时候要增加template相关的关键词。另外,需要注意的是:每个不同的模板实例都会有一个独有的static成员对象。

template
class Printer {public: explicit Printer(const T& param):t(param){} static int s_value;private: T t;};template
//注意这里的定义方式int Printer
::s_value = 1;Printer
pi(1);Printer
pi2(1);Printer
pd(1.0);pi.s_value += 1; //pi和pi2中的改变了,pd的没改变 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16

其实这个结论是显然的,static成员属于实例化后的类,不同的实例化当然有不同static成员。就像上面的例子一样,pi.s_value += 1只影响到了Printer<int>,而不会影响到Printer<double>

函数模板中的static局部变量也有类似的工作方式。

类模板成员函数实例化

为了节省资源,类模板实例化时并不是每个成员函数都实例化了,而是使用到了哪个成员函数,那个成员函数才实例化。

template
class Printer {public: explicit Printer(const T& param):t(param){} void print() { cout << t << endl; } private: T t; };class empty{};empty e;Printer
p(e); //ok
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

虽然成员函数print无法通过编译,但是因为没有使用到,也就没有实例化print,所以没有触发编译错误。

类模板别名

为了简化代码,我们可以使用typedef为类模板的某个实例定义一个别名,也可以使用using语句固定一个或多个类型参数(这有点偏特化的意思了)。

typedef std::pair
PairOfInt; //ok,为std::pair
定义了一个别名template
using WithNum = std::pair
; //ok,相当于定义了一个std::pair的偏特化PairOfInt poi; //实际类型,std::pair
WithNum
strs; //实际类型,std::pair
WithNum
ints; //实际类型,std::pair
1 2 3 4 5 6

特化与偏特化

类模板的特化与偏特化

就像函数模板重载那样,你可以通过特化(偏特化)类模板来为特定的类型指定你想要的行为。类模板的特化(偏特化)只需要模板名称相同并且特化列表<>中的参数个数与原始模板对应上即可,模板参数列表不必与原始模板相同模板名称相同。一个类模板可以有多个特化,与函数模板相同,编译器会自动实例化那个最特殊的版本。

template
//基本模板class S {public: void info() { printf("In base template\n"); }};template<> //特化class S
{ public: void info() { printf("In int specialization\n"); }};template
//偏特化class S
{public: void info() { printf("In pointer specialization\n"); }};template
//另外一个偏特化class S
{public: void info() { printf("In function specialization\n"); }};int func(int i) { return 2 * i;}S
s1;s1.info(); //调用base模板 S
s2;s2.info(); //调用int特化版本S
s3;s3.info(); //调用T*特化版本 S
s4;s4.info(); //调用函数特化版本 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

提供了所有类型实参的特化是完全特化,只提供了部分类型实参或者T的类型受限(例如:T*)的特化被认为是不完整的,所以也被称为偏特化完全特化的结果是一个实际的class,而偏特化的结果是另外一个同名的模板。

类模板成员特化

除了可以特化类模板之外,还可以对类模板中的成员函数和普通静态成员变量进行特化。

template
class S { public: void info() { printf(“In base template\n”); } static int code; }; template
int S
::code = 10;

template<>

int S<int>::code = 100; //普通静态成员变量的int特化

template<>

void S<int>::info() { //成员函数的int特化
printf(“In int specialization\n”);
}

S<float> s1;

s1.info(); //普通版本
printf(“Code is: %d\n”, s1.code); //code = 10

S<int> s2;

s2.info(); //int特化版本
printf(“Code is: %d\n”, s2.code); //code = 100

你可能感兴趣的文章
响应式布局 媒体查询
查看>>
H5 tab切换页面
查看>>
qt文本编辑器
查看>>
一个简单的socket程序运行与抓包查看
查看>>
设置 弹窗优先级
查看>>
VB.NET中LINQ TO List泛型查询语句(分组,聚合函数)
查看>>
阿里云linux挂载云盘
查看>>
通过PPA存储库在UBUNTU或LINUX MINT中安装ORACLE JAVA 8 [JDK8]
查看>>
分布式架构基石-TCP通信协议
查看>>
相机连拍
查看>>
poj 2976 Dinkelbach迭代法
查看>>
获取IOS屏幕尺寸大小
查看>>
java NIO ;mvn
查看>>
pexpect模块
查看>>
0302就业形势分析与思考
查看>>
补码总结
查看>>
matplotlib----初探------1模块导入与运行
查看>>
.NET 3.5 获取不全Cookie的问题
查看>>
C# 中自定义事件
查看>>
创建触发器和使用示例
查看>>