C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析

模板

模板把函数或类要处理的数据类型参数化,表现为参数的多态性,成为类属

个人思考:模板也是计算机的很重要的思想“抽象思想”的体现

模板解决的是逻辑结构相同,但具体数据元素类型不同的数据

 

参数化编程:

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第1张图片

参数化编程有效地降低了开发成本,减少了出错概率,这也是模板思想的起源

深入剖析:

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第2张图片

问题1:第12行和第15行调的是同一个函数吗?

函数模板与模板函数的辨析

   函数模板:就是定义的一个带有参数类型的函数

   模板函数:

      编译器会把第12行换成 myswap(a,b) ,第15行换成 myswap(c,d) ,而把这两个就叫做模板函数

所以在这里生成了不同的模板函数,第12行和第15行调的不是同一个函数

问题2:通过函数模板生成的模板函数会不会引起和函数重载的冲突?

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第3张图片

解释:函数模板不提供隐式类型转换,因此不许严格遵循T的类型定义

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第4张图片

所以类型严格匹配是模板函数调用的先决条件

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第5张图片

当普通函数和函数模板都符合调用规则的时候,优先使用普通函数;

因为普通函数在编译期间就生成了函数体

而模板函数需要在调用时,编译器才会编译

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第6张图片

在这种冲突的情况下,可以显式地调用模板函数

总结:

编译器在处理函数模板的时候,能够生成任意类型的函数

根据调用的时机产生不同的函数:编译器会堆函数模板进行二次编译,这是参数化编程的基础,也是成为编译时多态的由来

在声明的地方对模板本身进行编译,在调用的时候对参数化以后的具体调用进行编译

hpp文件的由来

泛型编程是C++出来之后新加的内容,即泛型编程是在分离式编译之后出现的

以下是把模板分离式声明与定义的示例:

.h文件

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第7张图片

.cpp文件

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第8张图片

主函数.cpp文件及运行结果

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第9张图片

解释为什么无法解析该函数?

因为在编译时模板并不能生成真正的二进制代码,而是在编译调用模板类或函数的CPP文件时才会去找对应的模板声明和实现,无在这种情况下编译器是不知道实现模板类或函数的CPP文件的存在,无法进行二次编译,所以它只能找到模板类或函数的声明而找不到实现,而只好创建一个符号寄希望于链接程序找地址。但模板类或函数的实现并不能被编译成二进制代码,结果链接程序找不到地址只好报错了。而如果把模板声明和实现放到一块,在编译调用模板类或函数的CPP文件时就会找到模板声明和实现,进行二次编译

"《C++编程思想》第15章(第300页)说明了原因:
模板定义很特殊。由template<…> 处理的任何东西都意味着编译器在当时不为它分配存储空间,它一直处于等待状态直到被一个模板实例告知。在编译器和连接器的某一处,有一机制能去掉指定模板的多重定义。所以为了容易使用,几乎总是在头文件中放置全部的模板声明和定义。"

比如像下面在定义中写死掉模板函数就会通过编译和链接,因为编译器在第一次编译的时候直接为它分配了空间,生成了二进制代码,所以链接程序可以找到它的代码,通过编译和链接

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第10张图片

所以出现了.hpp文件,将.h的声明与.cpp的定义混合放到.hpp文件中

name mangling的编译原理

caller1.cpp

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第11张图片

caller2.cpp

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第12张图片

main.cpp

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第13张图片

结果:

C++ 模板技术和STL实战开发(1)——STL实用编程技术(1)——模板机制剖析_第14张图片

为什么没有调用caller2?

因为myfunc(1)和myfunc(2)都会实例化模板函数为myfun(),只会生成一个,而如果要两个都做,那就加命名空间进行区分

这种在编译时只生成一个的技术就是Name Mangling

Name Mangling 是一种在编译过程中,将函数、变量的名称重新改编的机制。在 C++重载、namespace等操作符下,函数可以有同样的名字,编译器为了区分各个不同地方的函数,将各个函数通过编译器内定的算法,将函数改成唯一的名称。

你可能感兴趣的:(C++的STL使用和源码学习)