C++学习笔记之模板(1)——从函数重载到函数模板

一、函数重载

因为函数重载比较容易理解,并且非常有助于我们理解函数模板的意义,所以这里我们先来用一个经典的例子展示为什么要使用函数重载,这比读文字定义有效的多。

现在我们编写一个交换两个int变量值得函数,可以这样写:

1 void swap(int & a, int & b)
2 {
3    int tmp;
4
5    tmp = a;
6    a = b;
7    b = tmp;
8
9 }

假如我们现在想在与上面函数相同的文件中(可以理解为同一个main函数中)交换两个float变量呢,是不是需要重新整一个函数名,重新定义一个函数呢?当然是不需要!

可以直接这样写:

#include <iostream>

void swap(int & a, int & b);
void swap(float & a, float & b);

int main()
{
   using namespace std;

   int wallet1 = 300;
   int wallet2 = 350;
   float wallet3 = 125.33;
   float wallet4 = 235.82;

   cout << "Before swapping wallet1 and wallet2:" << endl;
   cout << "wallet1 = $" << wallet1 << endl;
   cout << "wallet2 = $" << wallet2 << endl;
   swap(wallet1, wallet2);
   cout << "After swapping wallet1 and wallet2:" << endl;
   cout << "wallet1 = $" << wallet1 << endl;
   cout << "wallet2 = $" << wallet2 << endl;

   cout << "Before swapping wallet3 and wallet3:" << endl;
   cout << "wallet3 = $" << wallet3 << endl;
   cout << "wallet4 = $" << wallet4 << endl;
   swap(wallet3, wallet4);
   cout << "After swapping wallet3 and wallet4:" << endl;
   cout << "wallet3 = $" << wallet3 << endl;
   cout << "wallet4 = $" << wallet4 << endl;

   return 0;
}

 void swap(int & a, int & b)
{
    int tmp;

    tmp = a;
    a = b;
    b = tmp;  

 }

 void swap(float & a, float & b)
{
    float tmp;

    tmp = a;
    a = b;
    b = tmp;  

 }

执行结果如下:

由此可以总结出函数重载的相关知识:函数重载就是允许存在多个同名的函数,但是函数的参数列表必须不同,即参数的类型或者数目不一样。如示例中的swap()函数有两个,但是输入的参数类型不一样,编译器就是根据参数列表(也称为函数特征)的不同来确定到底选择哪一个函数去执行!这样我们就可以为相同的操作,但是参数类型不同的函数只用同一个函数名,如示例中都是交换操作,只是参数类型不同而已。虽然函数重在很吸引人,但是很明显看出代码量比较大,所以不要滥用,仅当函数基本上执行相同的任务,但使用不同形式的数据时,才应采用函数重载……

试想一下,我们要交换char, int, short, double, float ...等等这许多变量,如果按照上述方式,正常人都疯了,于是函数模板款款而来……

二、函数模板

首先不说函数模板的定义,待洒家展示一下函数模板的神奇之处先,还是以事实说话,用函数模板实现上述功能:交换两个变量!

 1 #include <iostream>
 2
 3 template <typename T>
 4 void Swap(T &a, T &b);
 5
 6 int main()
 7 {
 8    using namespace std;
 9
10    int wallet1 = 300;
11    int wallet2 = 350;
12    cout << "Before swapping wallet1 and wallet2:" << endl;
13    cout << "wallet1 = $" << wallet1 << endl;
14    cout << "wallet2 = $" << wallet2 << endl;
15    Swap(wallet1, wallet2);
16    cout << "After swapping wallet1 and wallet2:" << endl;
17    cout << "wallet1 = $" << wallet1 << endl;
18    cout << "wallet2 = $" << wallet2 << endl;
19
20    double wallet3 = 125.33;
21    double wallet4 = 235.82;
22    cout << "Before swapping wallet3 and wallet3:" << endl;
23    cout << "wallet3 = $" << wallet3 << endl;
24    cout << "wallet4 = $" << wallet4 << endl;
25    Swap(wallet3, wallet4);
26    cout << "After swapping wallet3 and wallet4:" << endl;
27    cout << "wallet3 = $" << wallet3 << endl;
28    cout << "wallet4 = $" << wallet4 << endl;
29
30    char x = ‘a‘;
31    char y = ‘b‘;
32    cout << "Before swapping x and y:" << endl;
33    cout << "x = " << x << endl;
34    cout << "y = " << y << endl;
35    Swap(x, y);
36    cout << "After swapping wallet3 and wallet4:" << endl;
37    cout << "x = " << x << endl;
38    cout << "y = " << y << endl;
39    return 0;
40 }
41
42 template <typename T>
43 void Swap(T &a, T &b)
44 {
45     T tmp;
46     tmp = a;
47     a = b;
48     b = tmp;
49 }

执行如下:

这里我们实现了int, double, char类型的交换(但是其他任何类型的两个变量的交换均可实现,有兴趣的同学可以自己试一试,很简单,声明两个变量,调用一下函数就是了),但是可以看到,模板函数的定义就只是这么一小段:

1 template <typename T>
2 void Swap(T &a, T &b)
3 {
4     T tmp;
5     tmp = a;
6     a = b;
7     b = tmp;
8 }

好了,来好好解释一下,缓解同志们迫不及待的心情,嘿嘿……

所谓函数模板,就是让我们编写的函数独立于参数类型,只要函数执行的操作不变,就不用改变代码。函数模板以任意类型的方式来定义函数,以上面的Swap()模板函数为例:第一行指出要建立一个模板,类型为T,关键字template声明这是一个模板,关键字typename声明类型(有些老版本编译器不支持typename,用关键字class代替也一样),这里T是一个标志符,习惯上都用T(当然可以是S,Q,ABC等其他合法标识符),这个T代表着一种类型,但是具体代表什么类型(int?double?char?)是根据编译时输入的参数确定的,如上述main()函数的10,11,15行,编译器发现输入参数是int类型,那么T具体化为int, 同样第30,31,35,T就被具体化为char. 后面的代码就是交换两个变量的值。

要注意的是,函数模板本身并不是函数,它只是告诉编译器如何定义函数(这就是称之为模板的原因,提供一个框架而已),具体的函数是在编译过程中生成的。需要交换int的函数时,编译器按照模板的模式创建这样的函数,用int代替T,即函数是在编译过程中生成的,函数模板并不创建函数,只是创建一个模板去告诉编译器如何生成函数而已,最终的代码(编译之后)不包含任何模板,而只包含了为具体程序生成的实际函数。使用模板的好处是,它使得生成多个函数定义更简单、可靠。

专业一点的表述是,函数模板是通用的函数描述(ps:因为适合任何类型的参数),它们使用泛型来定义函数(ps:T可以带便任何类型),其中泛型可以用具体的类型(如int或者double)替换。通过将类型作为参数传递给模板,可是编译器生成该类型的函数。由于模板允许以泛型(刚刚ps中解释了泛型的感性理解哈)的方式编写程序,因此有时也被称为通用编程。由于类型是用参数表示的,因此模板特性也被称为参数化类型(parameterized types).

C++学习笔记之模板(1)——从函数重载到函数模板

时间: 2024-11-05 21:40:31

C++学习笔记之模板(1)——从函数重载到函数模板的相关文章

[ExtJS学习笔记]第七节 Extjs的组件components及其模板事件方法学习

本文地址:http://blog.csdn.net/sushengmiyan/article/details/38487519 本文作者:sushengmiyan -------------------------------------------------------------资源链接----------------------------------------------------------------------- 翻译来源  Sencha Cmd官方网站: http://ww

Mysql学习笔记(五)数学与日期时间函数

原文:Mysql学习笔记(五)数学与日期时间函数 学习内容: 1.数学函数 2.日期时间函数 这些函数都是很常用的函数...在这里进行简单的介绍... 数学函数: mysql> SELECT ABS(-32); //取绝对值函数 -> 32 这个函数可安全地使用于 BIGINT 值. mysql> SELECT SIGN(-32);//判断一个数是正数,负数,还是0..根据实际情况返回指定的数值.. -> -1 mysql> SELECT MOD(234, 10);//取模函

小猪猪C++笔记基础篇(六)参数传递、函数重载、函数指针、调试帮助

小猪猪C++笔记基础篇(六) ————参数传递.函数重载.函数指针.调试帮助 关键词:参数传递.函数重载.函数指针.调试帮助 因为一些事情以及自己的懒惰,大概有一个星期没有继续读书了,已经不行了,赶紧写一篇压压惊.把我文章抱走的同学留个言嘛. 函数在变成里面是一个非常重要的组成部分,那么这一部分我们先简单的介绍一下参数是如何传递进入函数,函数如何返回结果的.然后我们再来看看函数重载是个什么样的机制,最后在介绍一下所谓的函数指针到底是个什么东西.那么直接开始正题吧: 一.函数的参数传递 我们知道函

C++函数重载和函数模板

1.函数重载 这是小菜鸟写的一个例子. 函数重载应该注意以下几点: 1.1重载函数有类似的功能: 1.2只能以参数的类型(形参个数和类型)来重载函数, int max(int a,int b);float max(int a,int b);错 int max(int a,int b);float max(float a,float b);对 不能用形参的名字来重载: 1.3如果形参为引用类型或指针类型,则可以用关键字const来重载,即 int max(const int &a,const in

实验2:函数重载、函数模板、简单类的定义和实现

实验目的 1. 掌握c++中函数的声明.定义.调用和参数传递方式 2. 掌握c++中带有默认形参值的函数声明和定义方法 3. 理解函数重载,掌握c++中函数重载的实现方式 4. 理解函数模板,掌握c++中函数模板的简单使用 5. 理解面向对象的抽象和封装,掌握c++中类的定义.实现和使用方法 实验准备 1. 函数的声明.定义.调用.参数传递方法 2. 带有默认形参值的函数 3. 函数重载 4. 函数模板(9.1.1节 + 9.3节) 其中,9.3节,理解3个常用的排序算法和两个常用的查找算法 5

C++ 函数重载与函数匹配

<C++ Primer>笔记,整理关于函数重载与函数匹配的笔记. 函数重载 void func(int a); //原函数 void func(double a); //正确:形参类型不同 void func(int a, int b); // 正确:形参个数不同 int func(int a); //错误:只有返回类型不同 typedef int int32; void func(int32 a); //与原函数等价:形参类型相同 void func(const int a); //与原函数

函数重载(续)==》函数重载和函数指针在一起

函数重载与函数指针(这一块很重要,后续要继续学习): 当使用重载函数名对函数指针赋值时 根据重载规则挑选与函数指针参数列表一致的候选者 严格匹配候选者的函数类型与函数指针的函数类型 #include <iostream> using namespace std; void myFunc(int a) {     printf("a:%d\n",a); } void myFunc(char *p) {     printf("p:%s\n",p); } v

C++多态篇2——虚函数表详解之从内存布局看函数重载,函数覆盖,函数隐藏

上一篇C++多态篇1一静态联编,动态联编.虚函数与虚函数表vtable中,我在最后分析了虚函数与虚函数表的内存布局,在下一篇详细剖析虚函数及虚函数表的过程中,我发现有关函数重载,函数覆盖,函数重写和函数协变的知识也要理解清楚才能对虚函数表在内存中的布局,对派生类的对象模型以及对多态的实现有更深的理解. 所以这一篇我作为一篇过渡篇,也同时对我以前写过的一篇博文进行一个收尾.在C++继承详解之二--派生类成员函数详解(函数隐藏.构造函数与兼容覆盖规则)文章中,我对函数覆盖,重载,重写提了一下,但是没

位运算+引用+const+new/delete+内联函数、函数重载、函数缺省参数

一.位运算 应用: 1.判断某一位是否为1 2.只改变其中某一位,而保持其它位都不变 位运算操作: 1.& 按位与(双目): 将某变量中的某些位清0(与0位与)且同时保留其它位不变(与1位与):获取某变量中某一位(与其位与后判断是否为该数) 2.|  按位或(双目): 将某变量中的某些位置1(与1位或)且保留其它位不变 3.^  按位异或(双目): 将某变量中的某些位取反(与1异或)且保留其它位不变 异或运算特点: 如果 a^b=c,那么就有 c^b = a以及c^a=b.(穷举法可证---用于