阅读更多
模板函数定义的就是一种函数。既然是函数,那么就有输入数据和输出数据。和模板类的概念差不多,模板函数的初衷也是为了在函数操作上抽取共同的特性,屏蔽的是类型的不同和差异。
模板函数的反汇编示例:
#include
#include
template
type compare(type a, type b)
{
return a > b ? a : b;
};
int main(void) {
int v = compare(2, 3);
double v2 = compare(2.5, 3.5);
printf("v=%d,v2=%f", v, v2);
}
main():
080483e4: push %ebp
080483e5: mov %esp,%ebp
080483e7: and $0xfffffff0,%esp
080483ea: sub $0x20,%esp
11 int v = compare(2, 3);
080483ed: movl $0x3,0x4(%esp)
080483f5: movl $0x2,(%esp)
080483fc: call 0x8048444 (int, int)>
08048401: mov %eax,0x1c(%esp)
12 double v2 = compare(2.5, 3.5);
08048405: fldl 0x8048580
0804840b: fstpl 0x8(%esp)
0804840f: fldl 0x8048588
08048415: fstpl (%esp)
08048418: call 0x8048459 (double, double)>
0804841d: fstpl 0x10(%esp)
13 printf("v=%d,v2=%f", v, v2);
08048421: fldl 0x10(%esp)
08048425: fstpl 0x8(%esp)
08048429: mov 0x1c(%esp),%eax
0804842d: mov %eax,0x4(%esp)
08048431: movl $0x8048570,(%esp)
08048438: call 0x8048300
0804843d: mov $0x0,%eax
14 }
08048442: leave
08048443: ret
5 type compare(type a, type b)
compare(int, int):
08048444: push %ebp
08048445: mov %esp,%ebp
7 return a > b ? a : b;
08048447: mov 0x8(%ebp),%eax
0804844a: cmp 0xc(%ebp),%eax
0804844d: jle 0x8048454 (int, int)+16>
0804844f: mov 0x8(%ebp),%eax
08048452: jmp 0x8048457 (int, int)+19>
08048454: mov 0xc(%ebp),%eax
8 };
08048457: pop %ebp
08048458: ret
5 type compare(type a, type b)
compare(double, double):
08048459: push %ebp
0804845a: mov %esp,%ebp
0804845c: sub $0x10,%esp
0804845f: mov 0x8(%ebp),%eax
08048462: mov %eax,-0x8(%ebp)
08048465: mov 0xc(%ebp),%eax
08048468: mov %eax,-0x4(%ebp)
0804846b: mov 0x10(%ebp),%eax
0804846e: mov %eax,-0x10(%ebp)
08048471: mov 0x14(%ebp),%eax
08048474: mov %eax,-0xc(%ebp)
7 return a > b ? a : b;
08048477: fldl -0x8(%ebp)
0804847a: fldl -0x10(%ebp)
0804847d: fxch %st(1)
0804847f: fucomip %st(1),%st
08048481: fstp %st(0)
08048483: seta %al
08048486: test %al,%al
08048488: je 0x804848f (double, double)+54>
0804848a: fldl -0x8(%ebp)
0804848d: jmp 0x8048492 (double, double)+57>
0804848f: fldl -0x10(%ebp)
8 };
08048492: leave
08048493: ret
汇编代码表明,两个compare调用的函数地址并不是一致的。其中整数的compare地址是0x8048444,而double的地址是 0x8048459。这说明编译器在编译的时候帮我们同时生成了两个compare函数。所以说,模板类的本质就是在编译器增加判断处理工作的同时,减 少手工的重复劳动。模板函数不需要显示定义函数的参数类型,这是因为可以从入参判断出函数的类型。
#include
#include
template
class data_process {
type a;
type b;
public:
data_process(type m, type n) :
a(m), b(n) {
}
~data_process() {
}
type add() {
return a + b;
}
type sub() {
return a - b;
}
};
int main(void) {
data_process data1(1,2);
data_process data2(1.2, 2.3);
printf("v1=%d,v2=%f\n", data1.add(), data2.add());
}
main():
080484f4: push %ebp
080484f5: mov %esp,%ebp
080484f7: push %ebx
080484f8: and $0xfffffff0,%esp
080484fb: sub $0x50,%esp
24 data_process data1(1,2);
080484fe: movl $0x2,0x8(%esp)
08048506: movl $0x1,0x4(%esp)
0804850e: lea 0x48(%esp),%eax
08048512: mov %eax,(%esp)
08048515: call 0x80485b4 ::data_process(int, int)>
25 data_process data2(1.2, 2.3);
0804851a: fldl 0x8048710
08048520: fstpl 0xc(%esp)
08048524: fldl 0x8048718
0804852a: fstpl 0x4(%esp)
0804852e: lea 0x38(%esp),%eax
08048532: mov %eax,(%esp)
08048535: call 0x80485d0 ::data_process(double, double)>
26 printf("v1=%d,v2=%f\n", data1.add(), data2.add());
0804853a: lea 0x38(%esp),%eax
0804853e: mov %eax,(%esp)
08048541: call 0x804861a ::add()>
08048546: fstpl 0x28(%esp)
0804854a: lea 0x48(%esp),%eax
0804854e: mov %eax,(%esp)
08048551: call 0x8048608 ::add()>
08048556: fldl 0x28(%esp)
0804855a: fstpl 0x8(%esp)
0804855e: mov %eax,0x4(%esp)
08048562: movl $0x8048700,(%esp)
08048569: call 0x8048410
0804856e: lea 0x38(%esp),%eax
08048572: mov %eax,(%esp)
08048575: call 0x8048602 ::~data_process()>
0804857a: lea 0x48(%esp),%eax
0804857e: mov %eax,(%esp)
08048581: call 0x80485ca ::~data_process()>
08048586: mov $0x0,%eax
27 }
0804858b: mov -0x4(%ebp),%ebx
0804858e: leave
0804858f: ret
08048590: mov %eax,%ebx
26 printf("v1=%d,v2=%f\n", data1.add(), data2.add());
08048592: lea 0x38(%esp),%eax
08048596: mov %eax,(%esp)
08048599: call 0x8048602 ::~data_process()>
0804859e: lea 0x48(%esp),%eax
080485a2: mov %eax,(%esp)
080485a5: call 0x80485ca ::~data_process()>
080485aa: mov %ebx,%eax
080485ac: mov %eax,(%esp)
080485af: call 0x8048430 <_Unwind_Resume@plt>
9 data_process(type m, type n) :
data_process::data_process(int, int):
080485b4: push %ebp
080485b5: mov %esp,%ebp
10 a(m), b(n) {
080485b7: mov 0x8(%ebp),%eax
080485ba: mov 0xc(%ebp),%edx
080485bd: mov %edx,(%eax)
080485bf: mov 0x8(%ebp),%eax
080485c2: mov 0x10(%ebp),%edx
080485c5: mov %edx,0x4(%eax)
11 }
080485c8: pop %ebp
080485c9: ret
13 ~data_process() {
data_process::~data_process():
080485ca: push %ebp
080485cb: mov %esp,%ebp
14 }
080485cd: pop %ebp
080485ce: ret
080485cf: nop
9 data_process(type m, type n) :
data_process::data_process(double, double):
080485d0: push %ebp
080485d1: mov %esp,%ebp
080485d3: sub $0x10,%esp
080485d6: mov 0xc(%ebp),%eax
080485d9: mov %eax,-0x8(%ebp)
080485dc: mov 0x10(%ebp),%eax
080485df: mov %eax,-0x4(%ebp)
080485e2: mov 0x14(%ebp),%eax
080485e5: mov %eax,-0x10(%ebp)
080485e8: mov 0x18(%ebp),%eax
080485eb: mov %eax,-0xc(%ebp)
10 a(m), b(n) {
080485ee: mov 0x8(%ebp),%eax
080485f1: fldl -0x8(%ebp)
080485f4: fstpl (%eax)
080485f6: mov 0x8(%ebp),%eax
080485f9: fldl -0x10(%ebp)
080485fc: fstpl 0x8(%eax)
11 }
080485ff: leave
08048600: ret
08048601: nop
13 ~data_process() {
data_process::~data_process():
08048602: push %ebp
08048603: mov %esp,%ebp
14 }
08048605: pop %ebp
08048606: ret
08048607: nop
15 type add() {
data_process::add():
08048608: push %ebp
08048609: mov %esp,%ebp
16 return a + b;
0804860b: mov 0x8(%ebp),%eax
0804860e: mov (%eax),%edx
08048610: mov 0x8(%ebp),%eax
08048613: mov 0x4(%eax),%eax
08048616: add %edx,%eax
17 }
08048618: pop %ebp
08048619: ret
15 type add() {
data_process::add():
0804861a: push %ebp
0804861b: mov %esp,%ebp
16 return a + b;
0804861d: mov 0x8(%ebp),%eax
08048620: fldl (%eax)
08048622: mov 0x8(%ebp),%eax
08048625: fldl 0x8(%eax)
08048628: faddp %st,%st(1)
17 }
0804862a: pop %ebp
0804862b: ret
针对每一个类型,模板的构造函数、析构函数、成员函数都要独立生成,这从上面的函数地址就可以看出来。所以模板的本质就是对 不同数据类型的相似性操作进行共同属性提取,合成模板。在应用的时候,编译器根据我们使用中的数据类型独立生成每一个类,构建每一个基本运算变量和运算函 数,仅此而已。