关于模板函数声明与定义的问题[通俗易懂]

c++primer上说:c++模板函数的声明与定义通常放在头文件中,而普通的函数通常是声明放在头文件中,定义放在源文件中,为什么会有这样的区别呢?模板函数与普通成员函数到底有什么区别?测试代码:tem.h#ifndef_TEM_H#define_TEM_HtemplateTadd(Ta,Tb);//{//returna+b;//}

大家好,又见面了,我是你们的朋友全栈君。

c++ primer上说:c++模板函数的声明与定义通常放在头文件中,而普通的函数通常是声明放在头文件中,定义放在源文件中,为什么会有这样的区别呢?模板函数与普通成员函数到底有什么区别?


测试代码:

tem.h

#ifndef _TEM_H
#define _TEM_H
template<typename T> T add(T a,T b);
//{

//return a+b;
//}
#endif

tem.cpp

using namespace std;
//#include “tem.h”

template <typename T> T add(T a, T b){return a+b;}
template int add(int,int);//实例化定义,必须放在模板定义的后面

main.cpp

#include <iostream>
#include “tem.h”
using namespace std;
int main()
{

cout << add(1,2);
return 0;
}

首先明确:

对普通函数来说,声明放在头文件中,定义放在源文件中,其它的地方要使用该函数时,仅需要包含头文件即可,因为编译器编译时是以一个源文件作为单元编译的,当它遇到不在本文件中定义的函数时,若能够找到其声明,则会将此符号放在本编译单元的外部符号表中,链接的时候自然就可以找到该符号的定义了。

而对模板函数来说,首先明确,模板函数是在编译器遇到使用模板的代码时才将模板函数实例化的。若将模板函数声明放在tem.h,模板定义放在tem.cpp,在main.cpp中包含头文件,调用add,按道理说应该实例化int add(int,int)函数,即生成add函数的相应代码,但是此时仅有声明,找不到定义,因此此时,它只会实例化函数的符号,并不会实例化函数的实现,即这个时候,在main.o编译单元内,它只是将add函数作为一个外部符号,这就是与普通函数的区别,对普通函数来说,此时的add函数已经由编译器生成相应的代码了,而对模板函数来说,此时并没有生成add函数对应的代码。此时编译main.cpp单元不会报错,但链接就会出现add函数未定义的错误。

因此,我们可以通过显式的实例化定义,即通过加上语句temmplate int add(int,int),编译器看到此语句将会生成add方法的int版本,这样的话,再链接就不会报错了。此外,这样做通常也能够提高编译的效率。试想,如果在tem.h文件内定义模板,假如有三个源文件均包含了该头文件且均使用了模板(假定均调用了add模板的int版本),则在这三个源文件内必然都会生成add函数的实例。显然效率不高。而如果像上面那样使用该模板,则只会在tem.cpp文件中实例化。

最后,对于类模板来说,也同样符合上面的原则。在实际类模板的实例化时,实际上是分几步的,首先当然是类模板的实例化,然后还有类成员函数的实例化,我们知道在类的定义中,其实只是声明了类的成员函数,编译器实际上是把类的成员函数编译成修改名称后的全局函数的,因此在使用类模板的时候,首先会初始化类模板,同时初始化类模板相应的构造函数,使用类模板的实例调用相应的成员函数时,才会初始化类模板的成员函数。如果类模板的成员函数的定义与类的定义不在同一个编译单元中(分离式编译),此时调用类的成员函数便会出现未定义的错误。而当我们像代码中那样在某个地方显式的调用它的时就不会出现此类问题了。

总结:其实很明显,明确一点就可以了,即编译器只要遇到使用模板函数时就会实例化相应的函数,若在此编译单元内没有模板函数的定义,它当然不能够实例化成功了。因此通常情况下模板函数的声明与定义均放在同一文件内,因此这样就保证了在使用模板的地方一定可以实例化成功了。同时,由编译器保证只生成某种类型的一个实例版本,不用担心重复实例化的问题。

c++primer上面只说了类模板的成员函数可以不在头文件中定义,却始终感觉说得不清不楚,因为实际上像普通类那样类的定义与实现放在不同的文件中的话,是会链接出错的。总之,若你不想出现任何未定的错误,将类模板或函数模板的定义与声明放在同一个文件中就行了。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/126778.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • docker 上传本地镜像_不同docker仓库镜像同步

    docker 上传本地镜像_不同docker仓库镜像同步前言之前通过docker搭建过jenkins+python3环境,如果想要在不同的机器上搭建一样的环境,就可以将之前搭建的镜像上传到镜像仓库,这样方便在不同的机器上快速搭建同一套环境。如果公开的话

    2022年7月30日
    3
  • fpga流水线设计思想_fpga视频容易入门

    fpga流水线设计思想_fpga视频容易入门流水线设计的思想来源是高流量,也就是说时间延迟固定的情况下尽可能的产生高的流量,使得整体的信号传输速率得到提升。这一概念我是最早在《高级FPGA设计——结构、实现和优化》(SteveKilts)一书中接触到的。作者在书中提到,高流量设计的抽象术语就是“流水线”。作者指出:流水线设计的优越性是新数据在前面的数据完成之前就可以进行处理。并给出一个例子,硬件实现计算一个数的三次方。这给出设计代码,用于下文分析比较。1.类似于软件的递归算法实现(非流水线结构)`timescale1ns/

    2022年8月14日
    1
  • 如何快速打开服务窗口及命令「建议收藏」

    如何快速打开服务窗口及命令

    2022年2月22日
    59
  • Hbase面试题(面经)整理

    Hbase面试题(面经)整理1.Hbase是什么?hbase的特点是什么?Hbase一个分布式的基于列式存储的数据库,基于Hadoop的hdfs存储,zookeeper进行管理。 Hbase适合存储半结构化或非结构化数据,对于数据结构字段不够确定或者杂乱无章很难按一个概念去抽取的数据。 Hbase为null的记录不会被存储。 基于的表包含rowkey,时间戳,和列族。新写入数据时,时间戳更新,同…

    2022年5月31日
    31
  • ios捕获异常并发送图片,便于解决bug[通俗易懂]

    ios捕获异常并发送图片,便于解决bug

    2022年1月23日
    49
  • 江门python培训机构

    江门python培训机构猿辅导接近完成新一轮融资:腾讯领投,估值75亿美元据路透社报道,知情人士称,在线教育平台猿辅导接近完成新一轮融资,估值约为75亿美元。本轮融资由腾讯控股公司和私募股权公司高瓴资本领投。对此,猿辅导向多知网表示“消息不准确”,暂未进一步说明。腾讯和高瓴资本均暂未对融资消息置评。教育部、财政部:实施教师在线教学能力提升行动教育部、财政部印发《关于做好2020年中小学幼儿园教师国家级培训计划组织实施工作的通知》。通知提出,实施教师在线教学能力提升行动,已经或计划开展在线教学的省(区、市),要通过线上培

    2022年6月9日
    45

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号