模板把函数或类要处理的数据类型参数化,表现为参数的多态性,成为类属
个人思考:模板也是计算机的很重要的思想“抽象思想”的体现
模板解决的是逻辑结构相同,但具体数据元素类型不同的数据
参数化编程:
参数化编程有效地降低了开发成本,减少了出错概率,这也是模板思想的起源
深入剖析:
问题1:第12行和第15行调的是同一个函数吗?
函数模板与模板函数的辨析
函数模板:就是定义的一个带有参数类型的函数
模板函数:
编译器会把第12行换成 myswap
所以在这里生成了不同的模板函数,第12行和第15行调的不是同一个函数
问题2:通过函数模板生成的模板函数会不会引起和函数重载的冲突?
解释:函数模板不提供隐式类型转换,因此不许严格遵循T的类型定义
所以类型严格匹配是模板函数调用的先决条件
当普通函数和函数模板都符合调用规则的时候,优先使用普通函数;
因为普通函数在编译期间就生成了函数体
而模板函数需要在调用时,编译器才会编译
在这种冲突的情况下,可以显式地调用模板函数
编译器在处理函数模板的时候,能够生成任意类型的函数
根据调用的时机产生不同的函数:编译器会堆函数模板进行二次编译,这是参数化编程的基础,也是成为编译时多态的由来
在声明的地方对模板本身进行编译,在调用的时候对参数化以后的具体调用进行编译
泛型编程是C++出来之后新加的内容,即泛型编程是在分离式编译之后出现的
以下是把模板分离式声明与定义的示例:
.h文件
.cpp文件
主函数.cpp文件及运行结果
解释为什么无法解析该函数?
因为在编译时模板并不能生成真正的二进制代码,而是在编译调用模板类或函数的CPP文件时才会去找对应的模板声明和实现,无在这种情况下编译器是不知道实现模板类或函数的CPP文件的存在,无法进行二次编译,所以它只能找到模板类或函数的声明而找不到实现,而只好创建一个符号寄希望于链接程序找地址。但模板类或函数的实现并不能被编译成二进制代码,结果链接程序找不到地址只好报错了。而如果把模板声明和实现放到一块,在编译调用模板类或函数的CPP文件时就会找到模板声明和实现,进行二次编译
"《C++编程思想》第15章(第300页)说明了原因:
模板定义很特殊。由template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。"
比如像下面在定义中写死掉模板函数就会通过编译和链接,因为编译器在第一次编译的时候直接为它分配了空间,生成了二进制代码,所以链接程序可以找到它的代码,通过编译和链接
所以出现了.hpp文件,将.h的声明与.cpp的定义混合放到.hpp文件中
caller1.cpp
caller2.cpp
main.cpp
结果:
为什么没有调用caller2?
因为myfunc(1)和myfunc(2)都会实例化模板函数为myfun
这种在编译时只生成一个的技术就是Name Mangling
Name Mangling 是一种在编译过程中,将函数、变量的名称重新改编的机制。在 C++重载、namespace等操作符下,函数可以有同样的名字,编译器为了区分各个不同地方的函数,将各个函数通过编译器内定的算法,将函数改成唯一的名称。