先看一段代码
#include<stdio.h>
class A
{
public:
virtual void PrintA()
{
printf("A\n");
};
virtual void PrintAA()
{
printf("AA\n");
};
};
class B
{
public:
virtual void PrintB()
{
printf("B\n");
}
};
class C:public A,public B
{
// int a;
public:
virtual void PrintA()
{
printf("CA\n");
};
virtual void PrintB()
{
printf("CB\n");
}
};
void main()
{
C *c = new C;
printf("%d",sizeof(C));//打印为8
A *a = c;
B *b = c;
printf("A:%d B:%d C:%d\n",a,b,c); //5648160 5648164 5648160 (10进制显示)
b->PrintB(); //CB
a->PrintA();//CA
a->PrintAA();//AA
}
看一下汇编代码
.text:0040F03B mov ecx, [ebp+var_28]
.text:0040F03E mov [ebp+var_18], ecx
.text:0040F041 mov edx, [ebp+var_18]
.text:0040F044 mov eax, [edx]
.text:0040F046 mov esi, esp
.text:0040F048 mov ecx, [ebp+var_18]
.text:0040F04B call dword ptr [eax]// b->PrintB()
.text:0040F04D cmp esi, esp
.text:0040F04F call __chkesp
.text:0040F054 mov ecx, [ebp+var_14]
.text:0040F057 mov edx, [ecx]
.text:0040F059 mov esi, esp
.text:0040F05B mov ecx, [ebp+var_14]
.text:0040F05E call dword ptr [edx] //a->PrintA()
.text:0040F060 cmp esi, esp
.text:0040F062 call __chkesp
.text:0040F067 mov eax, [ebp+var_14]
.text:0040F06A mov edx, [eax]
.text:0040F06C mov esi, esp
.text:0040F06E mov ecx, [ebp+var_14]
.text:0040F071 call dword ptr [edx+4] //a->PrintAA()
.text:0040F074 cmp esi, esp
.text:0040F076 call __chkesp
.text:0040F07B mov ecx, [ebp+var_C]
.text:0040F07E mov large fs:0, ecx
.text:0040F085 pop edi
.text:0040F086 pop esi
.text:0040F087 pop ebx
.text:0040F088 add esp, 68h
.text:0040F08B cmp ebp, esp
.text:0040F08D call __chkesp
.text:0040F092 mov esp, ebp
.text:0040F094 pop ebp
.text:0040F095 retn
.text:0040F095 _main endp
先看一下大小,如果C只有一个基类,那它的大小就是4,上一次,说明了。而这有两个基类,那它为什么是8。很明显,由于A,B都有虚函数,所以,在C是其实有两个虚表。
看看打印,printf("A:%d B:%d C:%d\n",a,b,c);A: 5648160 B:5648164 C:5648160,而为什么a,b不一样。这会和虚表有关。
A *a = c;
B *b = c;
这两句代码并不是简单的将c的值给a,b。而是编译器内部处理了。
相当于
a = c
b = c + 4 //4 是sizeof(A)
为什么是b是加4,class C:public A,public B.这就是原因
所以调用Print 时,以下是,(只是简单的解释,不能编译的)
call [(DWORD*)a[0]][0] // a->PrintA();
call [(DWORD*)a[0]][1] // a->PrintAA();
call [(DWORD*)b[0]][0] // b->PrintB();
总结一下:
class A
{
PVOID *vftable_A ;
}
class B
{
PVOID *vftable_B ;
}
class C:public A,public B
{
PVOID *vftable_C_FRO_A;
PVOID *vftable_C_FRO_B;
}