用汇编的眼光看C++(之虚函数) (二)

2014-11-24 12:43:49 · 作者: · 浏览: 1
00408870)

82: }

上面是一段函数调用的代码,代码可以稍微有点长。不过没有关系,我们可以按照代码的行数一行一行地去进行说明和理解。

76行: 我们创建了employee类型的一个变量p,这个可以从后面的employee的构造函数可以看出来

77行: 我们创建了manager类型的一个变量,这个也可以从后面的manager的构造函数看出

78行: 我们创建一个指针临时变量e,它保存了变量p的地址,这一句也比较简单

79行: 我们发现79句下面共有7句汇编,其中第三句、第六句、第七句是平衡堆栈的时候用的,和我们的调用没有关系。那么call的edx是什么东西呢?原来函数调用的顺序是这样的:edx -> [ecx] ->[ebp-0x18],不知道大家看明白了没有。在内存的第一个字节记录一个指向print函数指针的指针,也就是edx。通过这个edx,我们就可以查找到位于edx地址的内容是什么。后来我们提取出来后发现[edx]的内容正是我们要查找的print函数地址。这里相当于一个二次寻址的过程。

80行: 我们重新对临时变量e进行了赋值,此时e保存的是变量m的地址

81行: 我们发现此时的寻找过程和79行惊奇地一致,原因就在于edx的内容不同罢了。也就是指向函数指针的指针发生了变化而已。

试想一下,如果没有这个virtual函数,以上这段代码会发生什么差别呢?

76: employee p;

0040127D lea ecx,[ebp-10h]

00401280 call @ILT+45(employee::employee) (00401032)

00401285 mov dword ptr [ebp-4],0

77: manager m;

0040128C lea ecx,[ebp-14h]

0040128F call @ILT+65(manager::manager) (00401046)

00401294 mov byte ptr [ebp-4],1

78: employee* e = &p;

00401298 lea eax,[ebp-10h]

0040129B mov dword ptr [ebp-18h],eax

79: e->print();

0040129E mov ecx,dword ptr [ebp-18h]

004012A1 call @ILT+5(employee::print) (0040100a)

80: e = &m;

004012A6 lea ecx,[ebp-14h]

004012A9 mov dword ptr [ebp-18h],ecx

81: e->print();

004012AC mov ecx,dword ptr [ebp-18h]

004012AF call @ILT+5(employee::print) (0040100a)

82: }

76: employee p;

0040127D lea ecx,[ebp-10h]

00401280 call @ILT+45(employee::employee) (00401032)

00401285 mov dword ptr [ebp-4],0

77: manager m;

0040128C lea ecx,[ebp-14h]

0040128F call @ILT+65(manager::manager) (00401046)

00401294 mov byte ptr [ebp-4],1

78: employee* e = &p;

00401298 lea eax,[ebp-10h]

0040129B mov dword ptr [ebp-18h],eax

79: e->print();

0040129E mov ecx,dword ptr [ebp-18h]

004012A1 call @ILT+5(employee::print) (0040100a)

80: e = &m;

004012A6 lea ecx,[ebp-14h]

004012A9 mov dword ptr [ebp-18h],ecx

81: e->print();

004012AC mov ecx,dword ptr [ebp-18h]

004012AF call @ILT+5(employee::print) (0040100a)

82: }

很遗憾,这里就没有了动态查找的过程,所有的打印函数最终都指向了函数employee::print,此时多态性也不复存在了。