用汇编的眼光看c++(之模板函数)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing @163.com】
如果说模板类定义的是一种数据类型,那么模板函数定义的就是一种函数。既然是函数,那么就有输入数据和输出数据。和模板类的概念差不多,模板函数的初衷也是为了在函数操作上抽取共同的特性,屏蔽的是类型的不同和差异。我们可以通过下面一个简单的代码说明问题:
- int int_compare(int a, int b)
- {
- return a > b ? a : b;
- }
- double double_compare(double a, double b)
- {
- return a > b ? a : b;
- }
- template <typename type>
- type compare(type a, type b)
- {
- return a > b ? a : b;
- }
- 246: int i_value = compare(2, 3);
- 00401458 push 3
- 0040145A push 2
- 0040145C call @ILT+10(compare) (0040100f)
- 00401461 add esp,8
- 00401464 mov dword ptr [ebp-4],eax
- 247: double d_value = compare(2.3, 3.1);
- 00401467 push 4008CCCCh
- 0040146C push 0CCCCCCCDh
- 00401471 push 40026666h
- 00401476 push 66666666h
- 0040147B call @ILT+5(compare) (0040100a)
- 00401480 add esp,10h
- 00401483 fstp qword ptr [ebp-0Ch]
- 248: }
如果参数类型是 class类型呢? 我们可以试一试。首先定义基本class:
- class data
- {
- int value;
- public:
- explicit data(int m): value(m) {}
- ~data() {}
- int get_value() { return value;}
- int operator > (data& d) {return this->get_value() > d.get_value();}
- };
- 256: data m(4), n(2);
- 0040148D push 4
- 0040148F lea ecx,[ebp-10h]
- 00401492 call @ILT+40(data::data) (0040102d)
- 00401497 mov dword ptr [ebp-4],0
- 0040149E push 2
- 004014A0 lea ecx,[ebp-14h]
- 004014A3 call @ILT+40(data::data) (0040102d)
- 004014A8 mov byte ptr [ebp-4],1
- 257: data p = compare(m,n);
- 004014AC mov eax,dword ptr [ebp-14h]
- 004014AF push eax
- 004014B0 mov ecx,dword ptr [ebp-10h]
- 004014B3 push ecx
- 004014B4 lea edx,[ebp-18h]
- 004014B7 push edx
- 004014B8 call @ILT+15(compare) (00401014)
- 004014BD add esp,0Ch
- 258: }
257行: 我们调用模板函数compare, 函数地址为0x401014,注意dx为p的地址,也就是堆栈临时变量的地址
为了看到算术符>重载,我们跟进compare函数:
- 241: return a > b ? a : b;
- 0040212B lea eax,[ebp+10h]
- 0040212E push eax
- 0040212F lea ecx,[ebp+0Ch]
- 00402132 call @ILT+55(data::operator>) (0040103c)
- 00402137 test eax,eax
- 00402139 je compare+53h (00402143)
- 0040213B lea ecx,[ebp+0Ch]
- 0040213E mov dword ptr [ebp-18h],ecx
- 00402141 jmp compare+59h (00402149)
- 00402143 lea edx,[ebp+10h]
- 00402146 mov dword ptr [ebp-18h],edx
- 00402149 mov eax,dword ptr [ebp-18h]
- 0040214C mov dword ptr [ebp-10h],eax
- 0040214F mov ecx,dword ptr [ebp-10h]
- 00402152 mov edx,dword ptr [ecx]
- 00402154 mov eax,dword ptr [ebp+8]
- 00402157 mov dword ptr [eax],edx
- 00402159 mov ecx,dword ptr [ebp-14h]
- 0040215C or ecx,1
- 0040215F mov dword ptr [ebp-14h],ecx
- 00402162 mov byte ptr [ebp-4],1
- 00402166 lea ecx,[ebp+0Ch]
- 00402169 call @ILT+25(data::~data) (0040101e)
- 0040216E mov byte ptr [ebp-4],0
- 00402172 lea ecx,[ebp+10h]
- 00402175 call @ILT+25(data::~data) (0040101e)
- 0040217A mov eax,dword ptr [ebp+8]
(1) 开头调用call 0x0040103C函数就是调用重载运算符函数,[ebp-18h]表示即将被复制的是a数据还是b数据
(2) 比较返回结果后,开始复制数据,具体见0x402157,其中临时变量[ebp-14h]和临时变量[ebp-4]的操作可以忽略
(3) 函数返回前,对临时变量a和b进行析构处理,见代码0x402169和代码0x402175。
注意:
(1)编写模板函数前先保证自己的函数是编写正确的
(2)模板函数的优先级低于非模板函数
(3)模板函数的类型可以是自定义类型,也可以是c、c++语言的基本类型
(4)模板函数的使用经常和类的算术运算符混合使用,注意技巧
(5)模板函数中涉及指针部分的内容,务必注意