0.测试环境
gcc version 5.4.0 20160609 (Ubuntu 5.4.0-6ubuntu1~16.04.10)
1.虚继承
代码语言:javascript复制
X
/
virtual / virtual
/
A B
/
/
/
C
`
代码语言:javascript复制class X{
public:
int i;
virtual void show()
{
cout<<"X"<<endl;
}
virtual ~X()
{
cout<<"~X";
}
};
class A:public virtual X{
public:
int j;
virtual void show()
{
cout<<"A"<<endl;
}
virtual ~A()
{
cout<<"~A";
}
};
class B:public virtual X{
public:
int d;
virtual void show()
{
cout<<"B"<<endl;
}
virtual ~B()
{
cout<<"~B";
}
};
class C:public A, public B{
public:
int k;
virtual void show()
{
cout<<"C"<<endl;
}
virtual ~C()
{
cout<<"~C";
}
};
void test()
{
B *b= new C;
b->show();
delete b;
}
1.1 test()函数对应的汇编代码如下
代码语言:javascript复制
_Z4testv: //test
.LFB1041:
.cfi_startproc
pushl �p //ebp压栈
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, �p //ebp=esp
.cfi_def_cfa_register 5
pushl �x //ebx压栈
subl $20, %esp //esp=esp-20
.cfi_offset 3, -12
subl $12, %esp
pushl $28 //malloc的内存大小, Class C Object的大小为28
call _Znwj //malloc内存
addl $16, %esp
movl �x, �x //ebx=eax, eax为malloc的内存的首地址,即C.this
subl $12, %esp
pushl �x //C的首地址压栈
call _ZN1CC1Ev //C::C()
addl $16, %esp
testl �x, �x //ebx&ebx
je .L36 //if ebx&ebx=0, jmp
leal 8(�x), �x //eax=C.this 8
/*
|-------|<-----C.this
| A |
|-------|<-----b
| B |
|-------|
| C |
|-------|
| X |
|-------|
*/
jmp .L37
.L36:
movl $0, �x
.L37:
movl �x, -12(�p) //b=C.this 8, 即b=BastTypeB.this, 对应的代码为b=new C;
movl -12(�p), �x //eax=b
movl (�x), �x //eax=vptr
movl (�x), �x //eax=vptr[0]
subl $12, %esp
pushl -12(�p) //b的地址压栈
call *�x //b->show()
addl $16, %esp
cmpl $0, -12(�p)
je .L39
movl -12(�p), �x //eax=b
movl (�x), �x //eax=vptr
addl $8, �x //eax=vptr 8
movl (�x), �x //eax=vptr[2], virtual机制
subl $12, %esp
pushl -12(�p) //b压栈
call *�x //call vptr[2], delete b
addl $16, %esp
.L39:
//略
1.2 _ZN1CC1Ev对应的汇编代码如下:
代码语言:javascript复制_ZN1CC1Ev: //C:C()
.LFB1053:
.cfi_startproc
pushl �p
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, �p
.cfi_def_cfa_register 5
subl $8, %esp
movl 8(�p), �x //eax=this
addl $20, �x //base type X的首地址
/*
|-------|<-----C.this
| A |
|-------|<-----b
| B |
|-------|
| C |
Offset 20 -->|-------|<-----eax
|vptr |
|-------|
*/
jmp .L37
subl $12, %esp
pushl �x //压栈
call _ZN1XC2Ev //X:X()
/* _ZN1XC2Ev对应的代码如下:
_ZN1XC2Ev: //X::X()
.LFB1044:
.cfi_startproc
pushl �p
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, �p
.cfi_def_cfa_register 5
movl $_ZTV1X 8, �x //dex=vptr4X
movl 8(�p), �x //eax=this
movl �x, (�x) //[this]=vptr4X
nop
popl �p
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
*/
addl $16, %esp
movl $_ZTT1C 4, �x //edx=VTT 4
movl 8(�p), �x //eax=this
subl $8, %esp
pushl �x
pushl �x
call _ZN1AC2Ev //A::A()
/*
_ZN1AC2Ev:
.LFB1047:
.cfi_startproc
pushl �p
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, �p
.cfi_def_cfa_register 5
movl 12(�p), �x //eax=VTT 4
movl (�x), �x //edx=VTT[1], edx=vptr
movl 8(�p), �x //eax=this
movl �x, (�x) //[this]=vptr
movl 8(�p), �x //eax=this
movl (�x), �x
subl $12, �x //eax=vptr-12,即vtable 0获取offset to X
movl (�x), �x //eax=vtable[0], eax=20
movl �x, �x //edx=eax
movl 8(�p), �x //eax=this
addl �x, �x //edx=this offset2X, 即edx=this 20
movl 12(�p), �x //eax=VTT 4
movl 4(�x), �x //eax=eax 4,即eax=VTT 8
movl �x, (�x) //[edx] =VTT 8,即设置X的vptr(construction vtable for A-in-C)
nop
popl �p
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
*/
addl $16, %esp
movl $_ZTT1C 12, �x //edx=VTT(VTT for C) 12
movl 8(�p), �x //eax=this
addl $8, �x //eax=eax 8,即base type B的地址
subl $8, %esp
pushl �x //PUSH VTT 12, the address of vptr(_ZTC1C8_1B 12)
pushl �x //PUSH B.this
call _ZN1BC2Ev //B::B()
/* 分析略
_ZN1BC2Ev:
.LFB1050:
.cfi_startproc
pushl �p
.cfi_def_cfa_offset 8
.cfi_offset 5, -8
movl %esp, �p
.cfi_def_cfa_register 5
movl 12(�p), �x
movl (�x), �x
movl 8(�p), �x
movl �x, (�x)
movl 8(�p), �x
movl (�x), �x
subl $12, �x
movl (�x), �x
movl �x, �x
movl 8(�p), �x
addl �x, �x
movl 12(�p), �x
movl 4(�x), �x
movl �x, (�x)
nop
popl �p
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
*/
addl $16, %esp
movl $_ZTV1C 12, �x //edx=VTT 12
movl 8(�p), �x //eax=this
movl �x, (�x) //[this]=VTT 12
movl $20, �x //edx=20
movl 8(�p), �x //eax=this
addl �x, �x //eax=this 20
movl $_ZTV1C 64, �x //edx=vptr4C
movl �x, (�x) //[this]=vptr4C
movl $_ZTV1C 36, �x
movl 8(�p), �x //eax=this
movl �x, 8(�x) //[this 8]=vptr4C
nop
leave
.cfi_restore 5
.cfi_def_cfa 4, 4
ret
.cfi_endproc
1.3 delete b对应的汇编代码如下:
大概意思就是:delete b,就是将base type class b的地址压栈,但是编译器生成的代码会做一层转换,自动将压栈的地址-8,即将C.this压栈,然后析构,然后free