我理解,只要你有一个多态基类,基类就应该定义一个虚拟析构函数。因此,当删除指向派生类对象的基类指针时,它将首先调用派生类的析构函数。如果我错了,请纠正我。
此外,如果基类析构函数是非虚拟的,那么删除指向派生对象的基类指针将是未定义的行为。如果我错了也纠正我。
所以我的问题是:为什么当基类析构函数非虚拟时,对象不会被正确销毁?
我假设这是因为虚拟函数具有某种表,每当调用虚拟函数时都会记住和查阅该表。编译器知道,当应该删除对象时,它应该首先调用派生析构函数。
我的假设正确吗?
考虑
struct Base {
void f() { printf("Base::f"); }
};
struct Derived : Base {
void f() { printf("Derived::f"); }
};
Base* p = new Derived;
p->f();
这会打印Base::f
,因为Base::f
不是虚拟的。现在对析构函数执行同样的操作:
struct Base {
~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
~Derived() { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();
这将打印基数::~基
数。现在,如果我们使析构函数成为虚拟函数,那么,与任何其他虚拟函数一样,将调用对象的动态类型的最终覆盖器。析构函数覆盖基类中的虚拟析构函数(即使其“名称”不同):
struct Base {
virtual ~Base() { printf("Base::~Base"); }
};
struct Derived : Base {
~Derived() override { printf("Derived::~Derived"); }
};
Base* p = new Derived;
p->~Base();
调用 p-
Derived::~Derived
Base::~Base
现在,delete表达式一般相当于一个析构函数调用,后跟一个内存释放函数调用。在这种特殊情况下,表达式
delete p;
相当于
p->~Base();
::operator delete(p);
因此,如果析构函数是虚拟的,那么这是正确的:它首先调用
Derived::~Derived
,然后在完成时自动调用Base::~Base
。如果析构函数不是虚拟的,那么可能的结果是只调用Base::~Base
。
如果在删除对象时变量的静态类型是 bas 类型,则将调用基类型的析构函数,但不调用子类的析构函数(因为它不是虚拟的)。
因此,基类分配的资源将被释放,但子类分配的资源不会被释放。
因此,对象不会被正确销毁。
您对该表的看法是正确的:它被称为虚拟方法表或“vtable”。但是析构函数是非虚拟的结果不是析构函数没有以正确的顺序调用,而是根本没有调用子类的析构函数!
在这些关于C 11/14标准的幻灯片中,在幻灯片15中,作者写道,“许多经典的编码规则不再适用于C 11中”。他提出了三个示例的列表,我同意三法则和内存管理。 然而,他的第二个例子是“具有虚拟成员的虚拟析构函数”(仅此而已)。这是什么意思?我知道必须将基类析构函数声明为虚拟,以便调用正确的析构函数,如果我们有类似的东西 这里很好地解释了:什么时候使用虚拟析构函数? 但是,如果您有虚拟成员,现在在C
我读过一些文章,正如他们所说,主要的虚拟析构函数用例是: > 派生类可能具有来自堆的动态数据分配,即“拥有”该数据对象。所以,他们需要在析构函数中使用一些删除例程。通过基类指针删除需要在所有派生类中声明析构函数,直到那些具有动态数据分配的析构函数(基类也需要它) 此类具有< code >虚拟方法。但这对我来说不清楚。仅仅通过基类指针调用< code >虚拟方法总是会导致派生实现最多的调用。他们唯一
在C 11中,我们能够声明一个析构函数是自动生成的: 此外,我们可以将析构函数声明为纯虚: 我的问题是:如何将析构函数声明为自动生成和纯虚拟?看起来以下语法不正确: 这一个也不是: 也不是这个: 编辑:关于问题目的的一些澄清。基本上,我希望一个空类是不可实例化的基类,但派生类是可实例化的,那么该类必须有一个纯虚拟析构函数。但另一方面,我不想在.cpp文件中提供定义。因此,我需要某种与等效的机制。我
每个人都知道基类的分解器通常必须是虚拟的。但是派生类的析构函数是什么?在 C 11 中,我们有关键字“override”,并且能够显式使用默认析构函数。 在子类的析构函数中同时使用关键字“覆盖”和“=默认”是否正确?在这种情况下,编译器会生成正确的虚拟析构函数吗? 如果是,那么我们是否可以认为这是好的编码风格,我们应该总是这样声明派生类的析构函数,以确保基类析构函数是虚的?
我一直在使用越来越多的C11,我遇到了一些我在任何地方都找不到的东西。当我们从基指针中删除派生类时,我们需要有虚拟析构函数;但有时父析构函数需要“纯”,这在C中是不可能的。所以,我的问题是,默认值是否可以用于虚拟析构函数?我已经试过了,而且效果不错,但我不知道它是否安全,因为互联网上没有任何关于它的信息。 编辑:为了澄清这个问题,我说的是使用
非常感谢你的帮助,noctilux