仅仅说一下C++的显式实例化

关于显式实例化的资料,网上很多,看了看大多都是你抄我,我抄你,或者照搬cpp primer plus的说法,看得还是稀里糊涂。
理解这个需要先了解一下C++程序的编译。
先说一下编译。我们的程序代码不能直接被计算机的CPU识别并运行,因此,必须把类似英文自然语言的程序代码经过编译器的处理,变成计算机能识别的机器代码。

而计算机的机器代码是很朴素的,没有那么多的华丽胡哨的东西,只有一些简单的比如寻找地址、取出数据,数据加减乘除运算等基本内容,什么类啊、函数啊这些东西最终都会转化为这些朴素的代码。

原则上,我们的程序代码都会被转化为机器代码,但是也不一定都是这样子。比如简单的 #include,机器语言没有这么高级的东西与之对应,这样的代码是由编译器处理的,编译器先把这个指令包含的文件内容添加到你的程序代码里面,然后再把整合后的代码编译成机器代码。绝对不会出现在运行阶段动态include自己代码需要的内容。

还有一个就是模板。你辛辛苦苦写的、看起来很复杂、很高大上的模板的代码也不会编译成机器码,如果你指望模板代码被编译成机器码,然后在运行的时候自动套用数据类型,那显然是想多了,计算机没有这么先进智能。

这么说来,如果你的模板函数或者模板类没有在自己的代码中用到,那么编译后的二进制机器码里面,也不会有它的存在。

模板就是一个说明书,这个说明书是给编译器看的,指导编译器在用到的时候生成具体的函数或者类,这个过程统称实例化(instantiation,我觉得翻译成实体化更便于理解,实例化这个词总感觉怪怪的)。

比如我们容易理解的隐式实例化,编译器发现Swap()函数只有对应的模板的时候,会自动根据参数类型、以及函数模板这个说明书的定义规则,生成一个具体的、针对特定数据类型的函数。这个时候,就有了具体的函数(和普通函数一模一样),而且这个函数是可以被编译为二进制代码的。

现在假设这个函数模板在一个头文件里面,而且这个头文件被很多cpp文件include,那么每一个cpp文件在编译的时候,都会被编译器实例化一份Swap函数的二进制代码,这样子,这些cpp文件被链接的时候,最终形成的可执行文件会增大很多,因为存在很多份相同的函数二进制代码。

解决的办法就是我们通过显式实例化,在其中一个文件里面实例化一份代码,然后其他cpp文件用到的时候,通过链接程序找到这个代码并调用它。这时候,模板和显式实例化显然必须是分开的,否则,如果显式实例化代码在模板的头文件里面,被include到无数个cpp文件里面,相当于又被每一个cpp文件实例化一次。

对于函数模板较为简单,我们假设有t.h文件包含了一个函数模板

template <typename T>
void printme(T t)
{
    cout<<t<<endl;
}

test.cpp和其他cpp文件调用了函数模板(也就是inlude “t.h”),如果只在cpp文件里面显式实例化template void printme(int);或者隐式实例化,那么这个显式实例化语句没有任何意义。

现在我们添加了一个t.cpp文件,在这个文件里面显式实例化了printme,那么这时候的代码在编译链接阶段就不会存在代码冗余了。

如下面:

//t.cpp
#include "t.h"
template void printme<int>(int);

调用函数的代码

#include <iostream>
#include "t.h"
using namespace std;

int main()
{
    printme(12);
    return 0;
}

如此以来,无论多少个cpp生成的二进制代码,调用的只有 t.cpp生成的那个二进制文件里面的printme代码
当然,这些变化在程序运行时候看不出来,只能通过编译后可执行文件的大小体现出来。
模板类的情况一样,不再赘述.

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值