来看下面的一段代码:
#include
class CShape
{
public:
CShape();
~CShape();
public:
virtual void print();
};
CShape::CShape()
{
}
CShape::~CShape()
{
}
void CShape::print()
{
printf("CShape::print\n");
}
class CRect : public CShape
{
public:
CRect();
~CRect();
public:
virtual void print();
};
CRect::CRect()
{
}
CRect::~CRect()
{
}
void CRect::print()
{
printf("CRect::print\n");
}
class CSquare : public CShape
{
public:
CSquare();
~CSquare();
public:
virtual void print();
};
CSquare::CSquare()
{
}
CSquare::~CSquare()
{
}
void CSquare::print()
{
printf("CSquare::print\n");
}
int main(int args, char** argv)
{
CShape* shape;
CRect rect;
CSquare square;
shape = ▭
shape->print();
shape = □
shape->print();
return 0;
}
对应的汇编代码如下:
.file "class.c"
.text
.align 2
.globl __ZN6CShapeC2Ev
.def __ZN6CShapeC2Ev; .scl 2; .type 32; .endef
__ZN6CShapeC2Ev:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movl $__ZTV6CShape+8, (%eax)
popl %ebp
ret
.align 2
.globl __ZN6CShapeC1Ev
.def __ZN6CShapeC1Ev; .scl 2; .type 32; .endef
__ZN6CShapeC1Ev:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movl $__ZTV6CShape+8, (%eax)
popl %ebp
ret
.align 2
.globl __ZN6CShapeD2Ev
.def __ZN6CShapeD2Ev; .scl 2; .type 32; .endef
__ZN6CShapeD2Ev:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movl $__ZTV6CShape+8, (%eax)
popl %ebp
ret
.align 2
.globl __ZN6CShapeD1Ev
.def __ZN6CShapeD1Ev; .scl 2; .type 32; .endef
__ZN6CShapeD1Ev:
pushl %ebp
movl %esp, %ebp
movl 8(%ebp), %eax
movl $__ZTV6CShape+8, (%eax)
popl %ebp
ret
.section .rdata,"dr"
LC0:
.ascii "CShape::print\12\0"
.text
.align 2
.globl __ZN6CShape5printEv
.def __ZN6CShape5printEv; .scl 2; .type 32; .endef
__ZN6CShape5printEv:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $LC0, (%esp)
call _printf
leave
ret
.align 2
.globl __ZN5CRectC2Ev
.def __ZN5CRectC2Ev; .scl 2; .type 32; .endef
__ZN5CRectC2Ev:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call __ZN6CShapeC2Ev
movl 8(%ebp), %eax
movl $__ZTV5CRect+8, (%eax)
leave
ret
L11:
L10:
.align 2
.globl __ZN5CRectC1Ev
.def __ZN5CRectC1Ev; .scl 2; .type 32; .endef
__ZN5CRectC1Ev:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call __ZN6CShapeC2Ev
movl 8(%ebp), %eax
movl $__ZTV5CRect+8, (%eax)
leave
ret
L14:
L13:
.align 2
.globl __ZN5CRectD2Ev
.def __ZN5CRectD2Ev; .scl 2; .type 32; .endef
__ZN5CRectD2Ev:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl $__ZTV5CRect+8, (%eax)
L18:
movl 8(%ebp), %eax
movl %eax, (%esp)
call __ZN6CShapeD2Ev
leave
ret
L16:
.align 2
.globl __ZN5CRectD1Ev
.def __ZN5CRectD1Ev; .scl 2; .type 32; .endef
__ZN5CRectD1Ev:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl $__ZTV5CRect+8, (%eax)
L23:
movl 8(%ebp), %eax
movl %eax, (%esp)
call __ZN6CShapeD2Ev
leave
ret
L21:
.section .rdata,"dr"
LC1:
.ascii "CRect::print\12\0"
.text
.align 2
.globl __ZN5CRect5printEv
.def __ZN5CRect5printEv; .scl 2; .type 32; .endef
__ZN5CRect5printEv:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $LC1, (%esp)
call _printf
leave
ret
.align 2
.globl __ZN7CSquareC2Ev
.def __ZN7CSquareC2Ev; .scl 2; .type 32; .endef
__ZN7CSquareC2Ev:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call __ZN6CShapeC2Ev
movl 8(%ebp), %eax
movl $__ZTV7CSquare+8, (%eax)
leave
ret
L28:
L27:
.align 2
.globl __ZN7CSquareC1Ev
.def __ZN7CSquareC1Ev; .scl 2; .type 32; .endef
__ZN7CSquareC1Ev:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl %eax, (%esp)
call __ZN6CShapeC2Ev
movl 8(%ebp), %eax
movl $__ZTV7CSquare+8, (%eax)
leave
ret
L31:
L30:
.align 2
.globl __ZN7CSquareD2Ev
.def __ZN7CSquareD2Ev; .scl 2; .type 32; .endef
__ZN7CSquareD2Ev:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl $__ZTV7CSquare+8, (%eax)
L35:
movl 8(%ebp), %eax
movl %eax, (%esp)
call __ZN6CShapeD2Ev
leave
ret
L33:
.align 2
.globl __ZN7CSquareD1Ev
.def __ZN7CSquareD1Ev; .scl 2; .type 32; .endef
__ZN7CSquareD1Ev:
pushl %ebp
movl %esp, %ebp
subl $4, %esp
movl 8(%ebp), %eax
movl $__ZTV7CSquare+8, (%eax)
L40:
movl 8(%ebp), %eax
movl %eax, (%esp)
call __ZN6CShapeD2Ev
leave
ret
L38:
.section .rdata,"dr"
LC2:
.ascii "CSquare::print\12\0"
.text
.align 2
.globl __ZN7CSquare5printEv
.def __ZN7CSquare5printEv; .scl 2; .type 32; .endef
__ZN7CSquare5printEv:
pushl %ebp
movl %esp, %ebp
subl $8, %esp
movl $LC2, (%esp)
call _printf
leave
ret
.def ___main; .scl 2; .type 32; .endef
.def __Unwind_SjLj_Resume; .scl 2; .type 32; .endef
.def ___gxx_personality_sj0; .scl 2; .type 32; .endef
.def __Unwind_SjLj_Register; .scl 2; .type 32; .endef
.def __Unwind_SjLj_Unregister; .scl 2; .type 32; .endef
.align 2
.globl _main
.def _main; .scl 2; .type 32; .endef
_main:
pushl %ebp
movl %esp, %ebp
pushl %edi
pushl %esi
pushl %ebx
subl $172, %esp
andl $-16, %esp
movl $0, %eax
addl $15, %eax
addl $15, %eax
shrl $4, %eax
sall $4, %eax
movl %eax, -156(%ebp)
movl -156(%ebp), %eax
call __alloca
movl $___gxx_personality_sj0, -100(%ebp)
movl $LLSDA24, -96(%ebp)
leal -92(%ebp), %eax
leal -24(%ebp), %edx
movl %edx, (%eax)
movl $L53, %edx
movl %edx, 4(%eax)
movl %esp, 8(%eax)
leal -124(%ebp), %eax
movl %eax, (%esp)
call __Unwind_SjLj_Register
call ___main
leal -56(%ebp), %eax
movl %eax, (%esp)
call __ZN5CRectC1Ev
leal -72(%ebp), %eax
movl %eax, (%esp)
call __ZN7CSquareC1Ev
leal -56(%ebp), %eax
movl %eax, -28(%ebp)
movl -28(%ebp), %eax
movl (%eax), %edx
movl -28(%ebp), %eax
movl %eax, (%esp)
movl (%edx), %eax
movl $1, -120(%ebp)
call *%eax
leal -72(%ebp), %eax
movl %eax, -28(%ebp)
movl -28(%ebp), %eax
movl (%eax), %edx
movl -28(%ebp), %eax
movl %eax, (%esp)
movl (%edx), %eax
call *%eax
leal -72(%ebp), %eax
movl %eax, (%esp)
call __ZN7CSquareD1Ev
leal -56(%ebp), %eax
movl %eax, (%esp)
call __ZN5CRectD1Ev
movl $0, -128(%ebp)
jmp L44
L53:
leal 24(%ebp), %ebp
movl -116(%ebp), %eax
movl %eax, -136(%ebp)
L45:
movl -136(%ebp), %edx
movl %edx, -132(%ebp)
leal -72(%ebp), %eax
movl %eax, (%esp)
call __ZN7CSquareD1Ev
movl -132(%ebp), %eax
movl %eax, -136(%ebp)
L47:
L49:
movl -136(%ebp), %edx
movl %edx, -140(%ebp)
leal -56(%ebp), %eax
movl %eax, (%esp)
call __ZN5CRectD1Ev
movl -140(%ebp), %eax
movl %eax, -136(%ebp)
L51:
movl -136(%ebp), %edx
movl %edx, (%esp)
movl $-1, -120(%ebp)
call __Unwind_SjLj_Resume
L44:
leal -124(%ebp), %eax
movl %eax, (%esp)
call __Unwind_SjLj_Unregister
movl -128(%ebp), %eax
leal -12(%ebp), %esp
popl %ebx
popl %esi
popl %edi
popl %ebp
ret
.section .gcc_except_table,"dr"
LLSDA24:
.byte 0xff
.byte 0xff
.byte 0x1
.uleb128 LLSDACSE24-LLSDACSB24
LLSDACSB24:
.uleb128 0x0
.uleb128 0x0
LLSDACSE24:
.text
.globl __ZTV7CSquare
.section .rdata$_ZTV7CSquare,"dr"
.linkonce same_size
.align 8
__ZTV7CSquare:
.long 0
.long __ZTI7CSquare
.long __ZN7CSquare5printEv
.globl __ZTV5CRect
.section .rdata$_ZTV5CRect,"dr"
.linkonce same_size
.align 8
__ZTV5CRect:
.long 0
.long __ZTI5CRect
.long __ZN5CRect5printEv
.globl __ZTV6CShape
.section .rdata$_ZTV6CShape,"dr"
.linkonce same_size
.align 8
__ZTV6CShape:
.long 0
.long __ZTI6CShape
.long __ZN6CShape5printEv
.globl __ZTI6CShape
.section .rdata$_ZTI6CShape,"dr"
.linkonce same_size
.align 4
__ZTI6CShape:
.long __ZTVN10__cxxabiv117__class_type_infoE+8
.long __ZTS6CShape
.globl __ZTI5CRect
.section .rdata$_ZTI5CRect,"dr"
.linkonce same_size
.align 4
__ZTI5CRect:
.long __ZTVN10__cxxabiv120__si_class_type_infoE+8
.long __ZTS5CRect
.long __ZTI6CShape
.globl __ZTI7CSquare
.section .rdata$_ZTI7CSquare,"dr"
.linkonce same_size
.align 4
__ZTI7CSquare:
.long __ZTVN10__cxxabiv120__si_class_type_infoE+8
.long __ZTS7CSquare
.long __ZTI6CShape
.globl __ZTS6CShape
.section .rdata$_ZTS6CShape,"dr"
.linkonce same_size
__ZTS6CShape:
.ascii "6CShape\0"
.globl __ZTS5CRect
.section .rdata$_ZTS5CRect,"dr"
.linkonce same_size
__ZTS5CRect:
.ascii "5CRect\0"
.globl __ZTS7CSquare
.section .rdata$_ZTS7CSquare,"dr"
.linkonce same_size
__ZTS7CSquare:
.ascii "7CSquare\0"
.def _printf; .scl 2; .type 32; .endef
从以上汇编代码可以看出:
1、编译器自动创建一份构造函数和析构函数;
2、构造函数初始化顺序为先调用父类构造函数,再执行本类的构造函数;
3、析构函数析构顺序为先执行本类析构函数,再调用父类的析构函数;
4、编译器为拥有虚函数的类自动插入一个虚表,大小为4字节,是类的第一个成员变量,该变量是隐含的,对程序员不可见但是可以访问;
5、在创建类对象时,编译器将自动调用构造函数和析构函数;
6、函数调用时第一个参数为this指针,这是编译器自动插入的;
7、虚表保存着当前类和其父类的关系,通过这种关系可以确定this指针的指向关系,从而正确的调用虚函数(好像理解不是很正确,编译器一开始就应该知道当前this指针指向谁);