模板如何做到声明和定义分离

首先我们在之前学习模板的时候说过,在使用模板的时候我们要做到声明和定义不分离,但是这是为什么呢?如果模板的声明和定义分离又会发生什么事情呢?

这是声明

这是定义

在进行编译之后,可以看到报了下面的错误

可以看到这是一个编译错误,那么如果我将这个函数模板替换成一个普通函数呢?

普通函数的声明

普通函数的定义

重新编译运行都是成功的。

那么这是为什么呢?

我们首先要知道编译器底层是怎么处理我们写的代码的

结合到我们刚刚写的函数,在第一部的时候,会将Stack.h中的iostream展开,同时在test.cpp和stack.cpp中将stack.h展开

然后第二步就是构成汇编代码。那么汇编在test.cpp中发现了两个函数调用

然后编译器就会生成一个汇编指令,上图中的注释和,其中的问好也就是这个函数定义的地址,因为需要这个函数的地址所以编译器会从这里往上去寻找,是否存在这样的函数。但是在这个stack.h和stack.cpp中都没有定义,但是具有声明,所以编译器会暂时让这里通过。如果连声明都没有就会直接报错。等到编译器对所有文件都进行了汇编操作之后,就到链接操作了。对于func函数在链接的时候,在stack.cpp中发现了func的函数地址,所以这里可以通过,,但是因为我们的Add函数模板并没有实质的生成一个Add函数(不知道T的类型),所以在链接的时候,编译器没有发现Add函数的函数地址,最后就报错了。为什么会出现这样的问题呢?归根到底,是因为编译器在汇编的时候是针对于每一个文件单独的进行汇编的,所以对于Stack.cpp来说并不知道要实例化的T类型,所以没有实例化成具体的函数,最后导致出错。

这也正是模板不能支持分离编译的原因。那么如何解决这个问题呢?

我们知道这里问题的所在就是在Stack.cpp中没有实例化Add函数,即在stack.h里面我知道Add函数要实例化成什么,但是没有定义,在Stack.cpp那里我有Add定义但是我不知道要实例化成什么。

那么解决这个问题的第一个方法也就是让在stack.cpp中的Add模板显示实例化。

由此可以知道模板不是真的不能声明和定义分离,你只要显示实例化了就可以。但是这样写有一个很大的缺陷,那就是如果我在主函数中将参数修改了呢?

那么为了不报错我就必须在显示实例化一个函数模板。以上的所有对于一个类模板也是成立的。如果我想要将一个类模板声明和定义分离,那么第一个解决方法也就是显示实例化。只不过类模板的显示实例化,只用写一个就能够实例化类里面所有的函数了。

那么除了这个方法之外呢?还有一个方法那就是我们删除stack.cpp函数,然后在stack.h文件里面,将声明放到上面,然后在下面完成完成对函数的定义。

所以如果我们要做到模板的声明和定义分离,那么可以使用的方法也就是那两个(对于类模板和函数模板都是这样)。

下面是一个类模板的定义:

类模板的声明

这是类模板的显式实例化

而对于类模板要做到长远一点的解决方法也是一样的将声明放到上面,将定义放到下面。

下面我们在来总结一下使用模板的缺陷和优点:

希望这篇博客能对你有所帮助,如果发现了任何错误欢迎指出。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值