Конечно, педантичный ответ C ++: «Стандарт ничего не говорит о vtbls или о том, как реализован полиморфизм».
Однако, на практике, да.Vtbl модифицируется до того, как тело деструктора базового класса начинает выполнение.
РЕДАКТИРОВАТЬ:
Вот как я использовал MSVC10, чтобы увидеть, как это происходит для меня.Во-первых, тестовый код:
#include <string>
#include <iostream>
using namespace std;
class Poly
{
public:
virtual ~Poly();
virtual void Foo() const = 0;
virtual void Test() const = 0 { cout << "PolyTest\n"; }
};
class Left : public Poly
{
public:
~Left()
{
cout << "~Left\n";
}
virtual void Foo() const { cout << "Left\n"; }
virtual void Test() const { cout << "LeftTest\n"; }
};
class Right : public Poly
{
public:
~Right() { cout << "~Right\n"; }
virtual void Foo() const { cout << "Right\n"; }
virtual void Test() const { cout << "RightTest\n"; }
};
void DoTest(const Poly& poly)
{
poly.Test();
}
Poly::~Poly()
{ // <=== BKPT HERE
DoTest(*this);
cout << "~Poly\n";
}
void DoIt()
{
Poly* poly = new Left;
cout << "Constructed...\n";
poly->Test();
delete poly;
cout << "Destroyed...\n";
}
int main()
{
DoIt();
}
Теперь установите точку останова на открывающей скобке для Poly
dtor.
Когда вы запускаете этот код на разрывы на открывающей скобке (незадолго до того, как тело конструктора начнет выполняться), вы можете взглянуть на vptr:
Также вы можете просмотреть разборку для Poly
dtor:
Poly::~Poly()
{
000000013FE33CF0 mov qword ptr [rsp+8],rcx
000000013FE33CF5 push rdi
000000013FE33CF6 sub rsp,20h
000000013FE33CFA mov rdi,rsp
000000013FE33CFD mov ecx,8
000000013FE33D02 mov eax,0CCCCCCCCh
000000013FE33D07 rep stos dword ptr [rdi]
000000013FE33D09 mov rcx,qword ptr [rsp+30h]
000000013FE33D0E mov rax,qword ptr [this]
000000013FE33D13 lea rcx,[Poly::`vftable' (13FE378B0h)]
000000013FE33D1A mov qword ptr [rax],rcx
DoTest(*this);
000000013FE33D1D mov rcx,qword ptr [this]
000000013FE33D22 call DoTest (13FE31073h)
cout << "~Poly\n";
000000013FE33D27 lea rdx,[std::_Iosb<int>::end+4 (13FE37888h)]
000000013FE33D2E mov rcx,qword ptr [__imp_std::cout (13FE3C590h)]
000000013FE33D35 call std::operator<<<std::char_traits<char> > (13FE3104Bh)
}
000000013FE33D3A add rsp,20h
000000013FE33D3E pop rdi
000000013FE33D3F ret
Перейдите на следующую строку, в тело деструктора, и еще раз посмотрите на vptr:
Теперь, когда мы вызываем DoTest
из тела деструктора, vtblуже был изменен, чтобы указывать на purecall_
, что генерирует ошибку подтверждения времени выполнения в отладчике: