64,266
社区成员
发帖
与我相关
我的任务
分享
#include <vector>
#include <iostream>
using namespace std;
class A
{
public:
A(char *pa):m_a(pa)
{
};
virtual ~A()
{
cout << "destructor of A" << endl;
destory();
}
protected:
virtual void destory()
{
cout << "destory A" << endl;
delete m_a;
}
protected:
char *m_a;
};
class B : public A
{
public:
B(char* pa, char *pb)
:A(pa), m_b(pb)
{
int a;
};
virtual ~B()
{
cout << "destructor of B" << endl;
destory();
}
protected:
virtual void destory()
{
cout << "destory B" << endl;
delete m_b;
}
private:
char *m_b;
};
int main(int argc, char* argv[])
{
A *ptr = new B(new char[4], new char[5]);
delete ptr;
return 0;
}
输出结果:
destructor of B
destory B
destructor of A
destory A
其实在父类析构函数中调用的虚函数一定是这个类的虚函数,所以A::~A()只会调用A::destory();
为什么呢?
下面是两个类析构函数的汇编码:
virtual ~B()
{
00BD1A30 push ebp
00BD1A31 mov ebp,esp
00BD1A33 push 0FFFFFFFFh
00BD1A35 push offset __ehhandler$??1B@@UAE@XZ (0BD5858h)
00BD1A3A mov eax,dword ptr fs:[00000000h]
00BD1A40 push eax
00BD1A41 sub esp,0CCh
00BD1A47 push ebx
00BD1A48 push esi
00BD1A49 push edi
00BD1A4A push ecx
00BD1A4B lea edi,[ebp-0D8h]
00BD1A51 mov ecx,33h
00BD1A56 mov eax,0CCCCCCCCh
00BD1A5B rep stos dword ptr es:[edi]
00BD1A5D pop ecx
00BD1A5E mov eax,dword ptr [___security_cookie (0BDA030h)]
00BD1A63 xor eax,ebp
00BD1A65 push eax
00BD1A66 lea eax,[ebp-0Ch]
00BD1A69 mov dword ptr fs:[00000000h],eax
00BD1A6F mov dword ptr [ebp-14h],ecx
00BD1A72 mov eax,dword ptr [ebp-14h]
00BD1A75 mov dword ptr [eax],offset B::`vftable' (0BD7804h)//这个初始化B类虚函数表
00BD1A7B mov dword ptr [ebp-4],0
cout << "destructor of B" << endl;
00BD1A82 mov esi,esp
00BD1A84 mov eax,dword ptr [__imp_std::endl (0BDB344h)]
00BD1A89 push eax
00BD1A8A push offset string "destructor of B" (0BD7844h)
00BD1A8F mov ecx,dword ptr [__imp_std::cout (0BDB348h)]
00BD1A95 push ecx
00BD1A96 call std::operator<<<std::char_traits<char> > (0BD119Ah)
00BD1A9B add esp,8
00BD1A9E mov ecx,eax
00BD1AA0 call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0BDB330h)]
00BD1AA6 cmp esi,esp
00BD1AA8 call @ILT+485(__RTC_CheckEsp) (0BD11EAh)
destory();
00BD1AAD mov ecx,dword ptr [ebp-14h]
B::destory:
00BD1AB0 call B::destory (0BD12BCh)
}
virtual ~A()
{
00BD18C0 push ebp
00BD18C1 mov ebp,esp
00BD18C3 sub esp,0CCh
00BD18C9 push ebx
00BD18CA push esi
00BD18CB push edi
00BD18CC push ecx
00BD18CD lea edi,[ebp-0CCh]
00BD18D3 mov ecx,33h
00BD18D8 mov eax,0CCCCCCCCh
00BD18DD rep stos dword ptr es:[edi]
00BD18DF pop ecx
00BD18E0 mov dword ptr [ebp-8],ecx
00BD18E3 mov eax,dword ptr [this]
00BD18E6 mov dword ptr [eax],offset A::`vftable' (0BD7810h) //这里初始化A类虚函数表
cout << "destructor of A" << endl;
00BD18EC mov esi,esp
00BD18EE mov eax,dword ptr [__imp_std::endl (0BDB344h)]
00BD18F3 push eax
00BD18F4 push offset string "destructor of A" (0BD7824h)
00BD18F9 mov ecx,dword ptr [__imp_std::cout (0BDB348h)]
00BD18FF push ecx
00BD1900 call std::operator<<<std::char_traits<char> > (0BD119Ah)
00BD1905 add esp,8
00BD1908 mov ecx,eax
00BD190A call dword ptr [__imp_std::basic_ostream<char,std::char_traits<char> >::operator<< (0BDB330h)]
00BD1910 cmp esi,esp
00BD1912 call @ILT+485(__RTC_CheckEsp) (0BD11EAh)
destory();
00BD1917 mov ecx,dword ptr [this]
00BD191A call A::destory (0BD12B7h)
}
(补充一点,存储每个含有虚函数的类对象时都会存储其虚函数表,一般在其起始位置)
所以任何一个类虚函数代码执行之前是先将对象存储位置中的虚函数表初始化为自己类的虚函数表。
所以在析构函数中调用的虚函数已经没有虚函数机制了。(这一点跟构造函数类似)
所以析构函数和构造函数中可以调用虚函数,只不过不会产生虚函数预期的行为罢了。
《Effective C++》有讲解。