重写析构函数C++
Override Destructor C++
来自C++常见问题解答:
[11.4] 我可以为我的类重载析构函数吗? 不。
我意识到这意味着您无法更改返回类型、参数类型或参数数量。我可能会在单词的语法上分裂头发,但是是否可以覆盖父级的析构函数?
class Child : public Parent {
public:
virtual Parent::~Parent() {
// New definition
}
};
就此而言,递归地这样做吗?
class Grandchild : public Child {
public:
Child::Parent::~Parent() {
// An even newer definition
}
};
我读过这篇文章和相关的文章,这让我想到因为析构函数不是继承的,所以它们不能被覆盖,但我从未见过它明确说明。
编辑:我更改了它以反映我想覆盖父级析构函数的事实,注意子项和孙子覆盖~Parent((。
我这样做的主要原因是维护 Parent 的接口,同时更改它的销毁方式(子类的全部原因(。我将有其他东西管理所有创建的 Parent,并在我选择的稍后时间显式调用它们的析构函数。
我可能在单词的语法上分裂头发
不,你绝对不是——这是两件截然不同的事情。
但是是否可以覆盖析构函数?
是的,实际上在许多情况下您必须这样做。为了使其适用于多态对象,您需要将基类析构函数声明为 virtual
,但是:
Parent const& p = Child();
将在作用域结束时正确调用p.~Child()
,因为Parent::~Parent
是虚拟的。
是的,可以重写类的析构函数。 实际上,在定义使用多态性的类层次结构时,必须在基类中声明虚拟析构函数。
析构函数的重写的工作方式与普通成员函数的重写的工作方式完全相同,因为当您通过指向基类的指针delete
对象来销毁对象时,派生类的析构函数将被正确调用。 这就是为什么必须在多态层次结构的基类中有一个虚拟析构函数的原因。
和虚拟成员方法之间存在差异,这与析构函数的virtual
性质无关。 也就是说,在执行这样的代码时:
class A
{
public:
virtual void Foo() {}
virtual ~A() {};
};
class B : public A
{
public:
void Foo() {};
~B() {}
};
int main()
{
A* a = new B;
a->Foo(); // B::Foo() is called
delete a; // B is destroyed via B::~B()
}
。调用 a->Foo()
时,将调用 B
中Foo()
的方法。 由于B::Foo()
没有显式调用A::Foo()
,因此不调用A::Foo()
。
但是,当对象通过 delete a;
销毁时,首先调用析构函数B::~B()
,然后在该完成后但在控制返回到程序之前,也会调用基类析构函数A::~A()
。
当然,当你考虑它时,这是显而易见的,同样这与析构函数的virtual
性质无关,但它的行为确实与正常的virtual
方法调用不同,所以我想我会指出它。
强制性标准报价:
[C++03] 12.4/6 : 析构函数
在执行析构函数的主体并销毁任何 在主体内分配的自动对象,X 类的析构函数 调用 X 直接成员的析构函数,调用 X 的析构函数 直接基类,如果 X 是派生最多的类的类型 (12.6.2(,它的析构函数调用 X 虚拟基的析构函数 类。调用所有析构函数时,就好像它们是使用限定名称引用的一样,也就是说,忽略任何可能的虚拟 重写更多派生类中的析构函数。基地和成员是 销毁顺序与完成顺序相反 构造函数(参见 12.6.2(。析构函数中的返回语句 (6.6.3( 可能不会直接返回给调用方;在移交控制权之前 对于调用方,将调用成员和基的析构函数。 数组元素的析构函数按与 它们的构造(见12.6(。
是的:你可以有virtual
析构函数,唯一的原因是在派生类中重写它们。
它看起来像这样:
class Parent {
public:
virtual ~Parent();
};
class Child : public Parent {
public:
virtual ~Child();
};
class Grandchild : public Child {
public:
~Grandchild(); // virtual is inherited here
};
请注意,析构函数不像普通函数那样被名称覆盖,因为该名称始终是要销毁其实例的类的名称。
另请注意,父类的析构函数也始终被调用,因此您不需要复制它们的清理代码:有关详细信息,请阅读成员对象和基类子对象的构造和销毁顺序。
术语
- 重写函数意味着在派生类中实现基类
virtual
函数。您根本无法更改签名(使用协变返回类型除外(。因此,覆盖始终与继承的虚函数具有相同的签名。 - 重载函数意味着实现具有相同名称(并且在某种意义上是相同作用域(的多个函数。因此,重载始终具有与其他具有相同名称的签名不同的签名,与虚拟调度没有直接关系,也不一定是继承的。
是的;只要您有一个可以使用对基类的引用来销毁的子类,您就可以并且应该使析构函数虚拟。 如果您不提供虚拟析构函数,静态代码分析工具甚至会抱怨。
请考虑以下示例:
class A
{
public:
A() { a = new int; }
virtual ~A() { delete a; }
private:
int *a;
};
class B final : public A
{
public:
B() { b = new int; }
~B() { delete b; }
private:
int *b;
};
int main()
{
A *a = new B();
delete a;
}
如果 A 的析构函数不是虚拟的,那么delete a
只会调用 A 的析构函数,并且最终会出现内存泄漏。但由于它是虚拟的,因此将按 -> ~A()
~B()
的顺序调用这两个析构函数。
- 什么时候调用组成单元对象的析构函数
- 如果C++类在类方法中具有动态分配,但没有构造函数/析构函数或任何非静态成员,那么它仍然是POD类型吗
- 内联映射初始化的动态atexit析构函数崩溃
- 什么时候调用析构函数
- 优先顺序:智能指针和类析构函数
- C++-明确何时以及如何调用析构函数
- 使用基类指针创建对象时,缺少派生类析构函数
- 在c++中使用向量时,如何调用构造函数和析构函数
- 重载运算符new[]的行为取决于析构函数
- 我需要知道编译器如何在cpp中使用析构函数
- 为什么在使用转换构造函数赋值后调用C++类的析构函数?
- 析构函数调用
- 通过引用传递-为什么要调用这个析构函数
- 对具有动态分配的内存和析构函数的类对象的引用
- 重载 -> shared_ptr 个实例中的箭头运算符<interface>,接口中没有纯虚拟析构函数
- C++成员的析构函数顺序与shared_ptr
- C++ 防止在映射中放置()时调用析构函数
- 在这种情况下显式调用时,std::cout 如何更改析构函数的行为?
- 调用析构函数以释放动态分配的内存
- 不命名构造函数和析构函数上的类型错误