c++类模板实例化验证

来源:互联网 发布:阿里云邮箱电话 编辑:程序博客网 时间:2024/06/08 16:58

摘要:

1. 首先通过PEview工具观察一般的代码编译链接过程;

2. 通过PEview工具和IDA工具验证类模板函数的实例化过程;

 

正文:

首先,看看下面的简单代码例子:

文件1,Main.cpp:

---------------------------

#include “play.h”#include <stdlib.h>int main() { play();system("pause");return 0;} 

文件2:play.h:

--------------------------------

#ifndef _play_h_#define _play_h_void play();#endif


文件3:play.cpp:

-------------------------------

#include <stdio.h>void play(){Printf(“I am the play\n”);}

上面三个文件存放在vs2008一个工程文件夹下面,按照这种方式生成的话,采用PEview查看main.obj的话,如下:

 

第二种写法,我们把play和main整合到一个文件中:

main.cpp:

-------------------------------------

void play(){printf("i am the play");}int main() {play();system("pause");return 0;} 

对上述代码进行编译,并且采用PEview查看生成的obj文件的话,可以发现:

对比上述的两者,可以发现前后少了一个.text标志,可以猜想得知:

         有代码定义的话,那么play这个会有Section Number的.text标志;

         如果没有定义的话,只是一个引用的话,那么play这个没有对应的标志;

小结:经过上面的实验性代码,我们知道每个.cpp文件会编译成为对应名字的.obj文件;

          如果某个.cpp中拥有某个函数的定义代码时,那么通过PEview查看的话,可以发现其对应的

          名字的Section Number是.text;反之,某个.cpp中只是调用某个函数,而没有定义的话,那么

          用PEview查看只能看到名字(如上的?play@@YAXXZ),但是对应的Section Number为空;

 

有了上面的经验,我们来看看类的函数的实例化过程。我们编译下面几个文件中的代码:

文件1:test.h:

template<class T> class A { public:      void f(); //这里只是个声明};

文件2:test.cpp:

#include "test.h"#include <stdio.h>template<class T> void A<T>::f() //模板的实现,但注意:不是具现{ printf(" in test\n");}

文件3:main.cpp:

int main() { A<int> a; a.f();system("pause");return 0;}


在vs2008中F7编译上述文件,发现如下的错误:
call_template.obj : error LNK2019: 无法解析的外部符号"public: void __thiscall A<int>::f(void)" (?f@?$A@H@@QAEXXZ),该符号在函数_main 中被引用

也就是函数A<int>::f(void)在call_template.cpp中被引用,但却没有在其他obj文件中被定义。按照我们的设想,该函数的定义应该会出现在test.obj中,

通过PEview.exe查看test.obj文件,并没有发现?f@?$A@H@@QAEXXZ这个符号。这也意味着test.obj中关于A<T>::f()的代码并没有编译。

 

网上查找后,得知模板并不是直接编译为可执行代码,需要经过具象化的过程,然后才是代码的编译。根据c++标准,采用惰性具象化的机制,

即如果在实现该模板的.cpp文件中没有用到模板的具现体时,编译器就懒得去具现化。

 

作为验证,假设我们在test.cpp文件中增加相应的具现体代码,如下:

 

#include "test.h"#include <stdio.h>template<class T> void A<T>::f() //模板的实现,但注意:不是具现{ printf(" in test\n");}void showme(){A<int> b;b.f();}

此处的showme函数对模板进行具现化,编译器看到该具现体时,完成void A<int>::f()的编译。通过PEview查看test.obj,可以发现:

在.text段,出现?f@?$A@H@@QAEXXZ代号的函数实现体。如此main函数在引用时,link函数就可以在test.obj中找到对应的实现。

解决上述模板编译问题的一个基本举措: 将test.h和test.cpp合在一起,也即模板的声明和其对应的实现应该放在一起。

如果采用IDA来查看A<int>::f()有没有被定义,就更直接了:
 
如上,在IDA 6.1版本中,打开test.obj文件后,直接可以在标签Exports中查看其导出的符号。

 

 

0 0
原创粉丝点击
热门问题 老师的惩罚 人脸识别 我在镇武司摸鱼那些年 重生之率土为王 我在大康的咸鱼生活 盘龙之生命进化 天生仙种 凡人之先天五行 春回大明朝 姑娘不必设防,我是瞎子 毛风衣叠久了怎么办 黑色的衣服沾毛怎么办 雪纺裙子弄上油怎么办 内衣买小了怎么办妙招 长裤衬衫裙邹了怎么办 100棉衬衣皱了怎么办? 短袖t恤袖口大了怎么办 短袖底下卷边了怎么办 棉质短袖衫缩水怎么办 纯棉t恤缩水了怎么办 t恤缩水变小了怎么办 衣服掉在雨棚上怎么办 车衣密码锁忘记密码怎么办 衣服的铁拉链弯怎么办 去旅行衣服皱了怎么办 衣服抽绳出来了怎么办 裤子的绑带掉了怎么办 网纱裙的边卷了怎么办 堵奶宝宝吸不通怎么办 棉麻裙子掉毛怎么办 10个月宝宝吃手怎么办 婴儿连体衣长了怎么办 冰丝面料变长了怎么办 t恤袖口大了怎么办 长袖t恤袖子长了怎么办 机打的扣子掉了怎么办 四个月宝宝头扁怎么办 鞋子前面穿翘了怎么办 休完产假没人带怎么办 休完产假孩子吃奶怎么办 巴布豆童鞋里面臭了到底怎么办 连体裤有点卡档怎么办 宝宝连体衣扣子掉了怎么办 买衣服被骂了怎么办? 把人车刮了跑了怎么办 打工打不下去了怎么办 白色衣服变粉了怎么办 一量血压就紧张怎么办 一紧张就血压高怎么办 不在上班时间在单位受伤怎么办 生活过得太压抑怎么办