Can*_*ing 4 c++ polymorphism inheritance
我知道,只要你有一个多态基类,基类就应该定义一个虚析构函数.因此,当删除派生类对象的基类指针时,它将首先调用派生类的析构函数.如果我在这里错了,请纠正我.
另外,如果基类析构函数是非虚拟的,则删除指向派生对象的基类指针将是未定义的行为.如果我错了,请纠正我.
所以我的问题是:为什么确切地说,当基类析构函数是非虚拟的时,对象不会被正确销毁?
我假设这是因为虚拟函数具有某种表,无论何时调用虚函数,它都会被记忆和参考.并且编译器知道当一个对象应该被删除时,它应该首先调用派生的析构函数.
我的假设是正确的吗?
如果在删除对象时,变量的静态类型是bas类型,则将调用基类型的析构函数,但不会调用子类的析构函数(因为它不是虚拟的) .
因此,将释放由基类分配的资源,但子类分配的资源不会.
因此,不会正确地破坏对象.
您对该表是正确的:它被称为虚拟方法表或"vtable".但是析构函数是非虚拟的结果并不是没有以正确的顺序调用析构函数,而是根本没有调用子类的析构函数!
考虑
struct Base {
void f() { printf("Base::f"); }
};
struct Derived : Base {
void f() { printf("Derived::f"); }
};
Base* p = new Derived;
p->f();
Run Code Online (Sandbox Code Playgroud)
这打印Base::f,因为Base::f不是虚拟的。现在对析构函数做同样的事情:
struct Base {
~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
~Derived() { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();
Run Code Online (Sandbox Code Playgroud)
这打印Base::~Base. 现在,如果我们使析构函数成为虚拟的,那么与任何其他虚拟函数一样,对象的动态类型中的最终覆盖程序将被调用。析构函数覆盖基类中的虚拟析构函数(即使它的“名称”不同):
struct Base {
virtual ~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
~Derived() override { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();
Run Code Online (Sandbox Code Playgroud)
该调用p->~Base()实际上调用Derived::~Derived(). 由于这是一个析构函数,在它的主体完成执行后,它会自动调用基类和成员的析构函数。所以输出是
Derived::~Derived
Base::~Base
Run Code Online (Sandbox Code Playgroud)
现在,delete 表达式通常等同于调用析构函数,然后调用内存释放函数。在这种特殊情况下,表达式
delete p;
Run Code Online (Sandbox Code Playgroud)
相当于
p->~Base();
::operator delete(p);
Run Code Online (Sandbox Code Playgroud)
因此,如果析构函数是虚拟的,那么这样做是正确的:它Derived::~Derived首先调用,然后Base::~Base在完成后自动调用。如果析构函数不是虚拟的,则可能的结果是 onlyBase::~Base被调用。