}
};
intmain(void)
{
Mammal*mammalPtr=newHorse;
deletemammalPtr;
return0;
}
1、构造函数:
Mammal*mammalPtr=newHorse;的汇编代码如下:
0040121Dpush0Ch
0040121Fcalloperatornew(004096b0)
00401224addesp,4
00401227movdwordptr[ebp-18h],eax
0040122Amovdwordptr[ebp-4],0
00401231cmpdwordptr[ebp-18h],0
00401235jemain+54h(00401244)
00401237movecx,dwordptr[ebp-18h]
0040123Acall@ILT+170(Horse:
:
Horse)(004010af)
0040123Fmovdwordptr[ebp-24h],eax
00401242jmpmain+5Bh(0040124b)
00401244movdwordptr[ebp-24h],0
0040124Bmoveax,dwordptr[ebp-24h]
0040124Emovdwordptr[ebp-14h],eax
00401251movdwordptr[ebp-4],0FFFFFFFFh
00401258movecx,dwordptr[ebp-14h]
0040125Bmovdwordptr[ebp-10h],ecx
既然是研究构造函数机制,那么先忽略掉无关内容,
0040123Acall@ILT+170(Horse:
:
Horse)(004010af)
是这一段汇编代码在本问题中的主要内容。
即,在定义一个对象时会自动调用类的构造函数。
下面再来具体看Horse的构造函数是什么样的:
114:
Horse(){cout<<"\nHorseconstructor\n"<00401500pushebp
00401501movebp,esp
00401503push0FFh
00401505pushoffset__ehhandler$?
?
0Horse@@QAE@XZ(0041d989)
0040150Amoveax,fs:
[00000000]
00401510pusheax
00401511movdwordptrfs:
[0],esp
00401518subesp,44h
0040151Bpushebx
0040151Cpushesi
0040151Dpushedi
0040151Epushecx
0040151Fleaedi,[ebp-50h]
00401522movecx,11h
00401527moveax,0CCCCCCCCh
0040152Crepstosdwordptr[edi]
0040152Epopecx
0040152Fmovdwordptr[ebp-10h],ecx
00401532movecx,dwordptr[ebp-10h]
00401535call@ILT+45(Mammal:
:
Mammal)(00401032)
0040153Amovdwordptr[ebp-4],0
00401541moveax,dwordptr[ebp-10h]
00401544movdwordptr[eax],offsetHorse:
:
`vftable'(00430034)
0040154Apushoffset@ILT+70(std:
:
endl)(0040104b)
0040154Fpushoffsetstring"\nHorseconstructor\n"(0043001c)
00401554pushoffsetstd:
:
cout(00434eb0)
00401559call@ILT+220(std:
:
operator<<)(004010e1)
0040155Eaddesp,8
00401561movecx,eax
00401563call@ILT+160(std:
:
basic_ostream:
char_traits>:
:
operator<<)(004010a5)
00401568movdwordptr[ebp-4],0FFFFFFFFh
0040156Fmoveax,dwordptr[ebp-10h]
00401572movecx,dwordptr[ebp-0Ch]
00401575movdwordptrfs:
[0],ecx
0040157Cpopedi
0040157Dpopesi
0040157Epopebx
0040157Faddesp,50h
00401582cmpebp,esp
00401584call__chkesp(00409ba0)
00401589movesp,ebp
0040158Bpopebp
0040158Cret
去除无关内容。
仅保留函数调用:
114:
Horse(){cout<<"\nHorseconstructor\n"<00401535call@ILT+45(Mammal:
:
Mammal)(00401032)
00401559call@ILT+220(std:
:
operator<<)(004010e1)
00401563call@ILT+160(std:
:
basic_ostream:
char_traits>:
:
operator<<)(004010a5)
00401584call__chkesp(00409ba0)
0040158Cret
第一个call调用了基类的构造函数;第二个call调用重载运算符;第三个call调用输出语句输出;第四个call调用栈检查函数。
由此可见,Horse(){cout<<"\nHorseconstructor\n"<2、析构函数:
15:
deletemammalPtr;
0040125Emovedx,dwordptr[ebp-10h]
00401261movdwordptr[ebp-20h],edx
00401264moveax,dwordptr[ebp-20h]
00401267movdwordptr[ebp-1Ch],eax
0040126Acmpdwordptr[ebp-1Ch],0
0040126Ejemain+9Ah(0040128a)
00401270movesi,esp
00401272push1
00401274movecx,dwordptr[ebp-1Ch]
00401277movedx,dwordptr[ecx]
00401279movecx,dwordptr[ebp-1Ch]
0040127Ccalldwordptr[edx]
0040127Ecmpesi,esp
00401280call__chkesp(00409ba0)
00401285movdwordptr[ebp-28h],eax
00401288jmpmain+0A1h(00401291)
0040128Amovdwordptr[ebp-28h],0
去除无关内容。
仅保留函数调用:
15:
deletemammalPtr;
0040125Emovedx,dwordptr[ebp-10h]
00401261movdwordptr[ebp-20h],edx
00401264moveax,dwordptr[ebp-20h]
00401267movdwordptr[ebp-1Ch],eax
0040126Acmpdwordptr[ebp-1Ch],0
0040126Ejemain+9Ah(0040128a)
00401270movesi,esp
00401272push1
00401274movecx,dwordptr[ebp-1Ch]
00401277movedx,dwordptr[ecx]
00401279movecx,dwordptr[ebp-1Ch]
0040127Ccalldwordptr[edx]
00401280call__chkesp(00409ba0)
由于析构函数是个虚函数,所以先在虚函数表中查找出析构函数的地址,然后再对析构函数进行调用。
下面再来具体看Horse的析构函数是什么样的:
115:
virtual~Horse(){cout<<"\nHorsedestructor\n"<004027C0pushebp
004027C1movebp,esp
004027C3push0FFh
004027C5pushoffset__ehhandler$?
?
1Horse@@UAE@XZ(0041d9e9)
004027CAmoveax,fs:
[00000000]
004027D0pusheax
004027D1movdwordptrfs:
[0],esp
004027D8subesp,44h
004027DBpushebx
004027DCpushesi
004027DDpushedi
004027DEpushecx
004027DFleaedi,[ebp-50h]
004027E2movecx,11h
004027E7moveax,0CCCCCCCCh
004027ECrepstosdwordptr[edi]
004027EEpopecx
004027EFmovdwordptr[ebp-10h],ecx
004027F2moveax,dwordptr[ebp-10h]
004027F5movdwordptr[eax],offsetHorse:
:
`vftable'(00430034)
004027FBmovdwordptr[ebp-4],0
00402802pushoffset@ILT+70(std:
:
endl)(0040104b)
00402807pushoffsetstring"\nHorsedestructor\n"(004300a4)
0040280Cpushoffsetstd:
:
cout(00434eb0)
00402811call@ILT+220(std:
:
operator<<)(004010e1)
00402816addesp,8
00402819movecx,eax
0040281Bcall@ILT+160(std:
:
basic_ostream:
char_traits>:
:
operator<<)(004010a5)
00402820movdwordptr[ebp-4],0FFFFFFFFh
00402827movecx,dwordptr[ebp-10h]
0040282Acall@ILT+120(Mammal:
:
~Mammal)(0040107d)
0040282Fmovecx,dwordptr[ebp-0Ch]
00402832movdwordptrfs:
[0],ecx
00402839popedi
0040283Apopesi
0040283Bpopebx
0040283Caddesp,50h
0040283Fcmpebp,esp
00402841call__chkesp(00409ba0)
00402846movesp,ebp
00402848popebp
00402849ret
去除无关内容。
仅保留函数调用:
115:
virtual~Horse(){cout<<"\nHorsedestructor\n"<00402811call@ILT+220(std:
:
operator<<)(004010e1)
0040281Bcall@ILT+160(std:
:
basic_ostream:
char_traits>:
:
operator<<)(004010a5)
0040282Acall@ILT+120(Mammal:
:
~Mammal)(0040107d)
00402841call__chkesp(00409ba0)
00402849ret
第一个call调用重载运算符;第二个call调用输出函数;第三个call调用基类析构函数;第四个call调用栈检测函数,检测占空间有没有被破坏。
由此可见,子类析构函数会先运行用户所写的代码,运行完了后编译器在后面插入了调用基类析构函数的指令。
由此可以调用所有相关的析构函数。
这是构造函数为虚函数所发生的情况。
如果析构函数不是虚函数呢?
1、基类析构函数为虚函数,子类构造函数为非虚函数
classMammal
{
public:
Mammal()
{
cout<<"\nmammalconstructor\n"<}
virtual~Mammal()
{
cout<<"\nmammaldesturctor\n"<}
public:
intGetAge(void)const
{
returnitsAge;
}
voidSetAge(intnewAge)
{
itsAge=newAge;
}
intGetWeight(void)const
{
returnitsWeight;
}
voidSetWeight(intnewWeight)
{
itsWeight=newWeight;
}
public:
voidSpeek(void)const
{
cout<<"\nMammalSond!
\n"<}
voidSpeek(intspkTimes)const
{
cout<<"\nMammalSond:
"<}
virtualvoidSleep(void)const
{
cout<<"\nMammalSleep\n"<}
protected:
intitsAge;
intitsWeight;
};
classHorse:
publicMammal
{
public:
Horse(){cout<<"\nHorseconstructor\n"<~Horse(){cout<<"\nHorsedestructor\n"<public:
virtualvoidSleep(void)const
{
cout<<"\nHorseSleep\n"<}
};
intmain(void)
{
Mammal*mammalPtr=newHorse;
deletemammalPtr;
return0;
}
运行结果:
汇编代码:
15:
deletemammalPtr;
0040125Emovedx,dwordptr[ebp-10h]
00401261movdwordptr[ebp-20h],edx
00401264moveax,dwordptr[ebp-20h]
00401267movdwordptr[ebp-1Ch],eax
0040126Acmpdwordptr[ebp-1Ch],0
0040126Ejemain+9Ah(0040128a)
00401270movesi,esp
00401272push1
00401274movecx,dwordptr[ebp-1Ch]
00401277movedx,dwordptr[ecx]
00401279movecx,dwordptr[ebp-1Ch]
0040127Ccalldwordptr[edx]
0040127Ecmpesi,esp
00401280call__chkesp(00409ba0)
00401285movdwordptr[ebp-28h],eax
00401288jmpmain+0A1h(00401291)
0040128Amovdwordptr[ebp-28h],0
去除无关内容。
仅保留函数调用:
15:
deletemammalPtr;
0040125Emovedx,dwordptr[ebp-10h]
00401261movdwordptr[ebp-20h],edx
00401264moveax,dwordptr[ebp-20h]
00401267movdwordptr[ebp-1Ch],eax
0040126Acmpdwordptr[ebp-1Ch],0
0040126Ejemain+9Ah(0040128a)
00401270movesi,esp
00401272push1
00401274movecx,dwordptr[ebp-1Ch]
00401277movedx,dwordptr[ecx]
00401279movecx,dwordptr[ebp-1Ch]
0040127Ccalldwordptr[edx]
00401280call__chkesp(00409ba0)
结合输出结果由此课件,子类的析构函数虽然没有在前面加virtual但是由于基类的析构函数是virtual的,所以编译器自动将子类的构造函数也设置为virtual的,因此可以正常调用子类析构函数和基类析构函数。
2、基类析构函数为非虚函数,子类构造函数为虚函数
classMammal
{
public:
Mammal()
{
cout<<"\nmammalconstructor\n"<}
~Mammal()
{
cout<<"\nmammaldesturctor\n"<}
public:
intGetAge(void)const
{
returnitsAge;
}
voidSetAge(intnewAge)
{
itsAge=newAge;
}
intGetWeight(void)const
{
returnitsWeight;
}
voidSetWeight(intnewWeight)
{
itsWeight=newWeight;
}
public:
voidSpeek(void)const
{
cout<<"\nMammalSond!
\n"<}
voidSpeek(intspkTimes)const
{
cout<<"\nMammalSond:
"<}
virtualvoidSleep(void)const
{
cout<<"\nMammalSleep\n"<}
protected: