C++_进阶之函数模板_类模板

小说:小学生压岁钱统计表作者:乙开帝侯更新时间:2018-12-14字数:83826

其他人听了也觉得是啊,古加兽会飞,他们不会,如果等亚古兽输了的时候他们就麻烦了……

免费网上挂机赚钱

但是这还没有结束,那圆球猛然向着四周扩散出去,沿着这八根触角,几乎是在短短的一瞬间便是彻底的将那巨掌给包裹起来。
“放心吧,他出来也没用的,你和他一样一起去死吧。”刘皓冷哼一声直接聚集身上的气。

“先把这件事告诉公主,免得到时候说你我故作主张,如果明天出现的是李芳果,而且身体并无大碍,婚约正常进行,如果不是,立刻毁掉婚约,带公主回去。”

C++_进阶之函数模板_类模板


 C++_进阶之函数模板_类模板

第一部分

前言

  c++提供了函数模板(function template.)所谓函数模板,实际上是建立一个通用函数,其函数类型和形参类型不具体制定,用一个虚拟的类型来代表。这个通用函数就成为函数模板。凡是函数体相同的函数都可以用这个模板代替,不必定义多个函数,只需在模板中定义一次即可。在调用函数时系统会根据实参的类型来取代模板中的虚拟类型,从而实现不同函

数的功能。

  1)c++提供两种模板机制:函数模板和类模板
  2)类属 - 类型参数化,又称参数模板
    使得程序(算法)可以从逻辑上抽象,把被处理的对象(数据)类型作为参数传递。
总结:
  1)模板把函数或类要处理的数据类型参数化,表现为参数的多态性,成为类属。
  2)模板用于表达逻辑结构相同,但具体数据元素类型不同的数据对象的通用行为。

第二部分

1.函数模板

1.1为什么要有函数模板

需求:写n个函数,交换char类型、int类型、double类型变量的值。

案例:

 1 #include <iostream>
 2 using namespace std;
 3 /*
 4 void myswap(int &a, int &b)
 5 {
 6     int t = a;
 7     a = b;
 8     b = t;
 9 }
10 void myswap(char &a, char &b)
11 {
12     char t = a;
13     a = b;
14     b = t;
15 }
16 */
17 //template 关键字告诉C++编译器 我要开始泛型了.你不要随便报错  
18 //数据类型T 参数化数据类型
19 template <typename T>
20 void myswap(T &a, T &b)
21 {
22     T t;
23     t = a;
24     a = b;
25     b = t;
26 }
27 void main()
28 {
29     //char a = "c";
30     
31     int  x = 1;
32     int     y = 2;
33     myswap(x, y); //自动数据类型 推导的方式 
34 
35     float a = 2.0;
36     float b = 3.0;
37 
38     myswap(a, b); //自动数据类型 推导的方式 
39     myswap<float>(a, b); //显示类型调用 
40 
41     cout<<"hello..."<<endl;
42     system("pause");
43     return ;
44 }
View Code

1.2函数模板语法

函数模板定义形式

  template    < 类型形式参数表 >    

    类型形式参数的形式为:

      typename T1 ,  typename T2 , …… , typename Tn 

      或 class T1 ,  class T2 , …… , class Tn

 

函数模板调用

    myswap<float>(a, b);  //显示类型调用

    myswap(a, b); //自动数据类型推导 

1.3函数模板和模板函数

转自:函数模板和模板函数

1.4函数模板做函数参数

 1 #include<iostream>
 2 using namespace std;
 3 
 4 /*
 5     让你对int行数组 和字符数组排序
 6     函数模板本质:类型参数化
 7 */
 8 template <typename T, typename T2>
 9 int mySort(T *array, int size)
10 {
11     if (array == NULL)
12     {
13         return -1;
14     }
15     for (T2 i =0 ;i<size; i++)
16     {
17         for (T2 j =i+1; j<size; j++)
18         {
19             if (array[i] > array[j])
20             {
21                 T temp;
22                 temp = array[i];
23                 array[i] = array[j];
24                 array[j] = temp;
25             }
26         }
27     }
28     return 0;
29 }
30 template <typename T, typename T2>
31 int myPrintf(T *array, T2 size)
32 {
33     for (T2 i = 0; i<size; i++)
34     {
35         cout << array[i] << endl;
36     }
37     return 0;
38 }
39 void main21()
40 {
41     {//int类型
42         int myarray[] = { 22, 33,44, 43, 56, 2, 44, 76 };
43         int size = sizeof(myarray) / sizeof(*myarray);
44         mySort<int, int>(myarray, size);
45 
46         printf("排序之后:
");
47         myPrintf<int, int>(myarray, size);
48     }
49 
50     {
51         //char类型
52         char buf[] = "ggggggghhhhhjjjdfffzzzzvvv";
53         int len = strlen(buf);
54         mySort<char, int>(buf, len);
55         myPrintf<char, int>(buf, len);
56     }
57 
58     system("pause");
59 }
View Code

1.5函数模板遇上函数重载

函数模板和普通函数区别结论:

  (1)函数模板不允许自动类型转化

  (2)普通函数能够进行自动类型转换

函数模板和普通函数在一起,调用规则: 

  1 函数模板可以像普通函数一样被重载

  2 C++编译器优先考虑普通函数

  3 如果函数模板可以产生一个更好的匹配,那么选择模板

  4 可以通过空模板实参列表的语法限定编译器只通过模板匹配

以下代码对上面文字进行说明:

案例1:

 1 #include <iostream>
 2 using namespace std;
 3 
 4 template <typename T>
 5 void myswap(T &a, T &b)
 6 {
 7     T t;
 8     t = a;
 9     a = b;
10     b = t;
11     cout<<"myswap 模板函数do"<<endl;
12 }
13 void myswap(char &a, int &b)
14 {
15     int t;
16     t = a;
17     a = b;
18     b = t;
19     cout<<"myswap 普通函数do"<<endl;
20 }
21 
22 void main()
23 {
24     char cData = "a";
25     int  iData = 2;
26 
27     //myswap<int>(cData, iData);  //结论 函数模板不提供隐式的数据类型转换  必须是严格的匹配
28 
29     myswap(cData, iData); 
30     //myswap(iData, cData);
31     
32     cout<<"hello..."<<endl;
33     system("pause");
34     return ;
35 }
View Code

案例2:

 1 #include<iostream>
 2 using namespace std;
 3 
 4 //让类型参数化---》方便程序员进行编码
 5 //泛型编程
 6 //template告诉C++编译器,开始泛型编程,不要随便报错
 7 template <typename T>
 8 void myswap(T &a, T &b)
 9 {
10     T c;
11     c = a;
12     a = b;
13     b = c;
14     cout << "我是模板函数-----》" << endl;
15 }
16 void myswap(int a, char  c)
17 {
18     cout << "a:" << "c:" << c << endl;
19     cout << "我是普通函数-----》" << endl;
20 }
21 void main31()
22 {
23     int a = 10;
24     char c = "z";
25     myswap(a,c);//当普通函数调用,可以进行隐式的类型转化
26 
27     myswap(c, a);
28 
29     myswap(a, a);//调用函数模板,(本质:类型参数化) 将严格进行类型匹配,不会进行类型转化
30 
31 }
View Code

案例3:

 1 #include "iostream"
 2 using namespace std;
 3 
 4 int Max(int a, int b)
 5 {
 6     cout<<"int Max(int a, int b)"<<endl;
 7     return a > b ? a : b;
 8 }
 9 
10 template<typename T>
11 T Max(T a, T b)
12 {
13     cout<<"T Max(T a, T b)"<<endl;
14     return a > b ? a : b;
15 }
16 
17 template<typename T>
18 T Max(T a, T b, T c)
19 {
20     cout<<"T Max(T a, T b, T c)"<<endl;
21     return Max(Max(a, b), c);
22 }
23 
24 void main()
25 {
26     int a = 1;
27     int b = 2;
28 
29     cout<<Max(a, b)<<endl; //当函数模板和普通函数都符合调用时,优先选择普通函数
30     cout<<Max<>(a, b)<<endl; //若显示使用函数模板,则使用<> 类型列表
31 
32     cout<<Max(3.0, 4.0)<<endl; //如果 函数模板产生更好的匹配 使用函数模板
33 
34     cout<<Max(5.0, 6.0, 7.0)<<endl; //重载
35 
36     cout<<Max("a", 100)<<endl;  //调用普通函数 可以隐式类型转换 
37     system("pause");
38     return ;
39 }
View Code

案例4:

 1 /*
 2 函数模板和普通函数区别结论:
 3     函数模板不允许自动类型转化
 4     普通函数能够进行自动类型转换
 5 */
 6 
 7 /*函数模板和普通函数在一起,调用规则:
 8     1 函数模板可以像普通函数一样被重载
 9     2 C++编译器优先考虑普通函数
10     3 如果函数模板可以产生一个更好的匹配,那么选择模板
11     4 可以通过空模板实参列表的语法限定编译器只通过模板匹配
12 */
13 #include "iostream"
14 using namespace std;
15 
16 
17 int Max(int a, int b)
18 {
19     cout << "int Max(int a, int b)" << endl;
20     return a > b ? a : b;
21 }
22 
23 template<typename T>
24 T Max(T a, T b)
25 {
26     cout << "T Max(T a, T b)" << endl;
27     return a > b ? a : b;
28 }
29 
30 template<typename T>
31 T Max(T a, T b, T c)
32 {
33     cout << "T Max(T a, T b, T c)" << endl;
34     return Max(Max(a, b), c);
35 }
36 
37 
38 void main41()
39 {
40     int a = 1;
41     int b = 2;
42 
43     cout << Max(a, b) << endl; //当函数模板和普通函数都符合调用时,优先选择普通函数
44     cout << Max<>(a, b) << endl; //若显示使用函数模板,则使用<> 类型列表
45 
46     cout << Max(3.0, 4.0) << endl; //如果 函数模板产生更好的匹配 使用函数模板
47 
48     cout << Max(5.0, 6.0, 7.0) << endl; //重载
49 
50     cout << Max("a", 100) << endl;  //调用普通函数 可以隐式类型转换 
51     system("pause");
52     return;
53 }
View Code

1.6C++编译器模板机制剖析

思考:为什么函数模板可以和函数重载放在一块。C++编译器是如何提供函数模板机制的?

 

 1 #include<iostream>
 2 using namespace std;
 3 
 4 //1.cpp
 5 
 6 //g++ -S 1.cpp -o 1.s    变成汇编语言
 7 template <typename T>
 8 void myswap(T &a, T &b)
 9 {
10     T c;
11     c = a;
12     a = b;
13     b = c;
14     cout << "hello------" << endl;
15 }
16 //函数模板的调用,显示类型调用,自动类型推倒
17 void main51()
18 {
19     {
20         int x = 10;
21         int y = 20;
22         myswap<int>(x, y);//函数模板的显示类型调用
23 
24         
25         printf("x:%d y:%d 
", x, y);
26     }
27     {
28         char a = "a";
29         char b = "b";
30         myswap<char>(a, b);//函数模板的显示类型调用
31 
32         printf("x:%d y:%d 
", a, b);
33     }
34 
35 }
36 /*
37     原理:
38     C++编译器会根据你的调用来产生函数,如果是int型的会产生int型的函数
39     ,如果是char会产生,char型的函数,如果有的话,就不会产生了。
40 
41     C++编译器帮我们写了一个函数,经过两次编译,形成的
42 */
43 /*
44 函数模板机制结论
45 编译器并不是把函数模板处理成能够处理任意类的函数
46 编译器从函数模板通过具体类型产生不同的函数
47 编译器会对函数模板进行两次编译
48 在声明的地方对模板代码本身进行编译;在调用的地方对参数替换后的代码进行编译。
49 */

 首先补充一些知识:

  编译器编译原理:

    什么是gcc 

    

gcc(GNU C Compiler)编译器的作者是Richard Stallman,也是GNU项目的奠基者。

什么是gcc:gcc是GNU Compiler Collection的缩写。最初是作为C语言的编译器(GNU C Compiler),现在已经支持多种语言了,如C、C++、Java、Pascal、Ada、COBOL语言等

gcc支持多种硬件平台,甚至对Don Knuth 设计的 MMIX 这类不常见的计算机都提供了完善的支持

   gcc主要特征 

        

1)gcc是一个可移植的编译器,支持多种硬件平台

2)gcc不仅仅是个本地编译器,它还能跨平台交叉编译。

3)gcc有多种语言前端,用于解析不同的语言。

4)gcc是按模块化设计的,可以加入新语言和新CPU架构的支持

5)gcc是自由软件

 

   gcc编译过程 

预处理(Pre-Processing)

编译(Compiling)

汇编(Assembling)

链接(Linking)

Gcc *.c –o 1exe (总的编译步骤)

Gcc –E 1.c –o 1.i  //宏定义 宏展开

Gcc –S 1.i –o 1.s

Gcc –c 1.s –o 1.o  

Gcc 1.o –o 1exe

结论:gcc编译工具是一个工具链。。。。

 hello程序是一个高级C语言程序,这种形式容易被人读懂。为了在系统上运行hello.c程序,每条C语句都必须转化为低级机器指令。然后将这些指令打包成可执行目标文件格式,并以二进制形式存储器于磁盘中。

 

    gcc常用编译选项 

  

选项

作用

-o

产生目标(.i、.s、.o、可执行文件等)

-c

通知gcc取消链接步骤,即编译源码并在最后生成目标文件

-E

只运行C预编译器

-S

告诉编译器产生汇编语言文件后停止编译,产生的汇编语言文件扩展名为.s

-Wall

使gcc对源文件的代码有问题的地方发出警告

-Idir

将dir目录加入搜索头文件的目录路径

-Ldir

将dir目录加入搜索库的目录路径

-llib

链接lib库

-g

在目标文件中嵌入调试信息,以便gdb之类的调试程序调试

    练习

 

gcc -E hello.c -o hello.i(预处理)

gcc -S hello.i -o hello.s(编译)

gcc -c hello.s -o hello.o(汇编)

gcc hello.o -o hello(链接)

以上四个步骤,可合成一个步骤

gcc hello.c -o hello(直接编译链接成可执行目标文件)

gcc -c hello.cgcc -c hello.c -o hello.o(编译生成可重定位目标文件)

建议初学都加这个选项。下面这个例子如果不加-Wall选项编译器不报任何错误,但是得到的结果却不是预期的。

#include <stdio.h>

int main(void)

{

        printf("2+1 is %f", 3);

        return 0;

}

Gcc编译多个.c

hello_1.h

hello_1.c

main.c

一次性编译

gcc  hello_1.c main.c –o newhello

独立编译

gcc -Wall -c main.c -o main.o

gcc -Wall -c hello_1.c -o hello_fn.o

gcc -Wall main.o hello_1.o -o newhello

 

    模板函数反汇编观察  

    命令:g++ -S 7.cpp -o 7.s

    汇编语言:略过

  1     .file    "7.cpp"
  2     .text
  3     .def    __ZL6printfPKcz;    .scl    3;    .type    32;    .endef
  4 __ZL6printfPKcz:
  5 LFB264:
  6     .cfi_startproc
  7     pushl    %ebp
  8     .cfi_def_cfa_offset 8
  9     .cfi_offset 5, -8
 10     movl    %esp, %ebp
 11     .cfi_def_cfa_register 5
 12     pushl    %ebx
 13     subl    $36, %esp
 14     .cfi_offset 3, -12
 15     leal    12(%ebp), %eax
 16     movl    %eax, -12(%ebp)
 17     movl    -12(%ebp), %eax
 18     movl    %eax, 4(%esp)
 19     movl    8(%ebp), %eax
 20     movl    %eax, (%esp)
 21     call    ___mingw_vprintf
 22     movl    %eax, %ebx
 23     movl    %ebx, %eax
 24     addl    $36, %esp
 25     popl    %ebx
 26     .cfi_restore 3
 27     popl    %ebp
 28     .cfi_restore 5
 29     .cfi_def_cfa 4, 4
 30     ret
 31     .cfi_endproc
 32 LFE264:
 33 .lcomm __ZStL8__ioinit,1,1
 34     .def    ___main;    .scl    2;    .type    32;    .endef
 35     .section .rdata,"dr"
 36 LC0:
 37     .ascii "a:%d b:%d 12"
 38 LC1:
 39     .ascii "c1:%c c2:%c 12"
 40 LC2:
 41     .ascii "pause"
 42     .text
 43     .globl    _main
 44     .def    _main;    .scl    2;    .type    32;    .endef
 45 _main:
 46 LFB1023:
 47     .cfi_startproc
 48     .cfi_personality 0,___gxx_personality_v0
 49     .cfi_lsda 0,LLSDA1023
 50     pushl    %ebp
 51     .cfi_def_cfa_offset 8
 52     .cfi_offset 5, -8
 53     movl    %esp, %ebp
 54     .cfi_def_cfa_register 5
 55     andl    $-16, %esp
 56     subl    $32, %esp
 57     call    ___main
 58     movl    $0, 28(%esp)
 59     movl    $10, 24(%esp)
 60     movb    $97, 23(%esp)
 61     movb    $98, 22(%esp)
 62     leal    24(%esp), %eax
 63     movl    %eax, 4(%esp)
 64     leal    28(%esp), %eax
 65     movl    %eax, (%esp)
 66     call    __Z6myswapIiEvRT_S1_  //66  ===>126 
 67     movl    24(%esp), %edx
 68     movl    28(%esp), %eax
 69     movl    %edx, 8(%esp)
 70     movl    %eax, 4(%esp)
 71     movl    $LC0, (%esp)
 72     call    __ZL6printfPKcz
 73     leal    22(%esp), %eax
 74     movl    %eax, 4(%esp)
 75     leal    23(%esp), %eax
 76     movl    %eax, (%esp)
 77     call    __Z6myswapIcEvRT_S1_ //77 ===>155 
2018手机签到赚钱软件 狂赚不换ip挂机 谷歌网赚联盟网址 玩微信赚钱骗局 k2路由器刷固件赚钱 孕妇在家无聊怎么办 外汇投资技巧 大学生找兼职工作

编辑:王扁公

我要说两句: (0人参与)

发布