C++模板(函数模板 & 类模板)
模板编程可称范型编程,是一种忽视数据类型的编程方式,这样的好处是什么?且看下面一个例子:
简单使用
求解最值问题,返回两个值中的较大值:
int Max(int a, int b)
{
return a>b?a:b;
}
double Max(int a, int b)
{
return a>b?a:b;
}
string Max(string a,string b)
{
return a>b?a:b;
}
使用Max函数处理数据类型不同的变量时,不得不重复写相同函数体的函数,于是引入了模板编程,可将类型当作未知量,使用template <typename type>来修饰函数:
template <typename type>
type Max(type a, type b)
{
return a>b?a:b;
}
或者
template <class T>
void print(T data)
{
cout << data << endl;
}
这两种声明方法是等价的
调用方法分为隐式调用和显式调用
在main函数中隐式调用:
int main(void)
{
cout << Max(1, 2) << endl;
cout << Max(1.1,2.2) << endl;
cout << Max(string("ILoveYou"),string("IMissYou")) << endl;
return 0;
}
输出:
2
2.2
IMissYou
显式调用,使用<>传类型的参数,也就是在<>填写上数据类型,放到参数和函数名之间
int main(void)
{
cout << Max<int>(1, 2) << endl;
cout << Max<float>(1.1, 2.2) << endl;
cout << Max<string>("ILoveYou","IMissYou") << endl;
return 0;
}
输出:
2
2.2
IMissYou
函数模板
此处着重讨论函数模板和普通函数的使用注意点
如果在代码中存在同名的普通函数和模板函数:
int Max(int a, int b)
{
cout << "comman function..." << endl;
return a > b? a:b;
}
template <class T>
T Max(T a, T b)
{
cout << "function template..." << endl;
return a > b? a:b;
}
那么使用模板的显式调用时,调用的一定是模板函数,隐式调用时,优先调用类型确定的函数
int main(void)
{
cout << Max<int>(1, 2) << endl;
cout << Max(1, 2) << endl;
return 0;
}
如上所示,第一个Max调用模板函数,第二个Max调用普通函数
如果代码中存在同名的模板函数,但参数个数不同:
template <class T1, class T2, class T3>
void print(T1 one, T2 two, T3 three)
{
cout << "three types" << endl;
}
template <class T1, class T2>
void print(T1 one, T2 two, T2 three)
{
cout << "two types" << endl;
}
template <class T>
void print(T one, T two, T three)
{
cout << "one type" << endl;
}
这可以理解为函数模板的重载(类型个数的不同也可以认为是重载),在显式调用情况下:
int main(void)
{
print<int, double, string>(1, 1.1, string("AAA"));
print<int, double>(1, 1.22, 1.1);
print<int>(1, 2, 3);
return 0;
}
输出:
three types
two types
one type
这里要注意的是,数据类型要和参数匹配
隐式调用略显麻烦,有时发现多个模板都能使用,常常优先调用需要传参较少的函数模板,如下所示:
int main(void)
{
print(1, 1, 1);
return 0;
}
输出 one type
可见类型参数最少的模板(只要传入一个类型)被调用了,但如果参数的类型各不相同,那也只能调用3个类型参数的函数模板了:
int main(void)
{
print(1, 1.1, string("AAA"));
return 0;
}
输出: three types
类中的方法也可以应用函数模板:
class Test
{
public:
template <class T>
void print(T data) {
cout << data << endl;
}
};
同样可以忽视数据类型,调用时通过对象调用即可
函数模板的类型参数可以缺省,这和普通函数参数的缺省是一样的规则,只能从右往左缺省
int main(void)
{
printData<int>(1, string("Hello"));
return 0;
}
这里类型参数就有缺省,但是因为声明了默认参数,所以就将第二个类型认为是string
函数模板还可以向类型参数中传常量:
template <class T,size_t size>
void printArray(T* array)
{
for (int i=0;i<size;i++) {
cout << array[i] << " ";
}
cout << endl;
}
int main(void)
{
int num[3] = {1, 2, 3};
printArray<int, 3>(num);
return 0;
}
输出: 1 2 3
类模板
类也可以应用模板,类模板不是一个完整的类型,所以任何用到类名的地方都要用类名<未知类型>的方式使用,同时在多文件中不能分开写,定义和声明位于同一文件,可以写在.hpp文件中(声明和实现放在一起),并且类模板只支持显示调用方式
如下案例,对C++结构体使用模板:
template <class T1, class T2>
struct my_pair
{
T1 first;
T2 second;
};
int main(void)
{
my_pair<int,int> pairData = {1, 2};
cout << pairData.first << " " << pairData.second << endl;
my_pair<int, string>* p = new my_pair<int, string>;
p->first = 1;
p->second = "2";
cout << p->first << " " << p->second << endl;
return 0;
}
输出:
1 2
1 2
如下使用类模板:
template <class type1,class type2>
class Test
{
public:
// constructor
Test(type1 one,type2 two):one(one),two(two) {
}
void printTest();
protected:
type1 one;
type2 two;
};
template <class type1,class type2>
void Test<type1,type2>::printTest()
{
cout << one << " " << two << endl;
}
template <class type1, class type2>
class Data :public Test<type1,type2>
{
public:
Data(type1 one, type2 two) :Test<type1,type2>(one,two) {
}
protected:
};
int main(void)
{
Data<int,int> data(1,2);
data.printTest();
return 0;
}
上述代码中首先定义了一个使用template修饰的类模板,声明了变量、构造函数和方法,在实现类模板的方法时也必须加上template进行修饰,在声明Data类继承Test时,也必须加上template修饰,在实例化时,使用<>显式的指定出数据类型
C++模板(函数模板 & 类模板)的更多相关文章
- 3.2 STL中的函数对象类模板
*: STL中有一些函数对象类模板,如下所示: 1)例如要求两个double类型的x 和y 的积,可以: multiplies<double>()(x,y); 该表达式的值就是x*y的值. ...
- 【C++】模板简述(三):类模板
上文简述了C++模板中的函数模板的格式.实例.形参.重载.特化及参数推演,本文主要介绍类模板. 一.类模板格式 类模板也是C++中模板的一种,其格式如下: template<class 形参名1 ...
- 聊聊C++模板函数与非模板函数的重载
前言 函数重载在C++中是一个很重要的特性.之所以有了它才有了操作符重载.iostream.函数子.函数适配器.智能指针等非常有用的东西. 平常在实际的应用中多半要么是模板函数与模板函数重载,或者是非 ...
- C++ 类模板一(类模板的定义)
//类模版语法 #include<iostream> using namespace std; /* 类模板和函数模板深入理解 1.编译器并不是把函数模板处理成能处理任何类型的函数 2.编 ...
- C++入门经典-例9.3-类模板,简单类模板
1:使用template关键字不但可以定义函数模板,而且可以定义类模板.类模板代表一族类,它是用来描述通用数据类型或处理方法的机制,它使类中的一些数据成员和成员函数的参数或返回值可以取任意数据类型.类 ...
- VS自定义模板-以自定义类模板为样例
前言 在实际的工作过程中部分公司会要求开发人员在开发过程中需遵守一些开发规范,开发规范中主要包括文件的注释规范,项目.文件.变量的命名规范(例如驼峰规范)等等.例如我们代码规范中就有一项新增文件的文件 ...
- C++练习 | 单向链表类模板(包含类模板中静态变量初始化格式)
#include <iostream> #include <string> using namespace std; template <class T> clas ...
- C++ 函数模板&类模板详解
在 C++ 中,模板分为函数模板和类模板两种.函数模板是用于生成函数的,类模板则是用于生成类的. 函数模板&模板函数 类模板&模板类 必须区分概念 函数模板是模板,模板函数时 ...
- [Reprint] C++函数模板与类模板实例解析
这篇文章主要介绍了C++函数模板与类模板,需要的朋友可以参考下 本文针对C++函数模板与类模板进行了较为详尽的实例解析,有助于帮助读者加深对C++函数模板与类模板的理解.具体内容如下: 泛型编程( ...
- C++_进阶之函数模板_类模板
C++_进阶之函数模板_类模板 第一部分 前言 c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来 ...
随机推荐
- mybatis框架的连表查询one2one
mybatis 的连表查询one2one 1.可以通过主从表之间的关联查询通过主键两次 在resultMap映射中的association标签<association property=&quo ...
- 数字子串的和 str2int
UVA1673 这道题可以用广义后缀自动机,不过陈锋老师给我们讲了一个巧妙地方法,使得这道题可以用普通的后缀自动机做. 题目大意: 给出NNN个完全由数字组成的字符串.计算将这个NNN的字符串的所有子 ...
- heimaJava-网络编程
Java 网络编程 概念 网络编程可以让程序与网络上的其他设备中的程序进行数据交互 网络通信基本模式 常见的通信模式有如下两种形式,Client-Server(CS),Browser/Server(B ...
- pintia 3-7-5 逆波兰表达式求值 (20 分)
3-7-5 逆波兰表达式求值 (20 分) 逆波兰表示法是一种将运算符(operator)写在操作数(operand)后面 的描述程序(算式)的方法.举个例子,我们平常用中缀表示法描述的算式(1 + ...
- Kafka源码阅读系列——Producer
Producer Kafka源码的exmaple模块有一个Producer类,继承了Thread类,构造方法会指定topic,是否异步,是否幂等,配置Kafka集群信息,初始化一个KafkaProdu ...
- C#向其实进程子窗体发送指令
近日,想在自己的软件简单控制其它软件的最大化最小化,想到直接向进程发送指令,结果一直无效,经过Spy++发现,原来快捷方式在子窗体上,所以需要遍历子窗体在发送指令,以下为参考代码: 1 [DllImp ...
- MSVC设置版本
MSVC设置版本 在开发QT时,由于QT 5.12与MSVC 2017兼容,因此需要用MSVC 2017来编译使用QT 5.12的程序. 1 安装MSVC 2017 由于笔者电脑上安装的Visual ...
- 【StoneDB 模块介绍】服务器模块
[StoneDB 模块介绍]服务器模块 一.介绍 客户端程序和服务器程序本质上都是计算机上的一个进程,客户端进程向服务器进程发送请求的过程本质上是一种进程间通信的过程,StoneDB 数据库服务程序作 ...
- luac编译命令
luac -o out.lua 1.lua 可以不要后缀 luac -o out 1.lua
- windows微信如何双开
生活中存在同时使用两个微信的情况,一个工作一个生活,这时希望同时在电脑上登录两个账号.如何做到呢?步骤如下: 右键单击"微信"图标,选择属性,目标框内的路径就是微信安装路径,复制目 ...