gpt4 book ai didi

c++ - 如果我将一个基类的析构函数从非虚拟更改为虚拟,会发生什么?

转载 作者:IT老高 更新时间:2023-10-28 21:46:22 26 4
gpt4 key购买 nike

我遇到了一个析构函数是非虚的基类,尽管该基类有 1 个虚函数 fv()。这个基类也有很多子类。其中许多子类定义了自己的 fv()

我不知道程序中如何使用基类和子类的细节。我只知道程序运行良好,即使基类的析构函数应该是虚拟的。

我想将基类的析构函数从非虚拟更改为虚拟。但我不确定后果。那么,会发生什么?更改后我还需要做些什么来确保程序正常运行?

跟进:在我将基类的析构函数从非虚拟更改为虚拟后,程序未通过一个测试用例。
结果让我很困惑。因为如果基类的析构函数不是虚拟的,那么程序就不会多态地使用基类。因为如果不是,它会导致未定义的行为。例如,Base *pb = new Sub.
所以,我认为如果我将析构函数从非虚拟更改为虚拟,它不应该导致更多的错误。

最佳答案

除非有其他问题,否则析构函数的虚拟性不会破坏现有代码中的任何内容。它甚至可以解决一些问题(见下文)。但是,该类可能不会被设计为多态,因此向其析构函数添加 virtual 可以使其具有多态性,这可能是不可取的。尽管如此,您应该能够安全地向析构函数添加虚拟性,并且它本身不会引起任何问题。

说明

多态性允许这样做:

class A 
{
public:
~A() {}
};

class B : public A
{
~B() {}

int i;
};

int main()
{
A *a = new B;
delete a;
}

您可以将指针指向实际上是 B 类型的类的 A 类型的对象。例如,这对于拆分接口(interface)(例如 A)和实现(例如 B)很有用。但是 delete a; 会发生什么?

a 类型的对象 a 的一部分被销毁。但是 B 类型的部分呢?加上那部分有资源,他们需要被释放。那就是那里的内存泄漏。通过调用 delete a; 可以调用 A 类型的析构函数(因为 a 是指向 A 类型的指针) ,基本上你调用a->~a();B 类型的析构函数永远不会被调用。如何解决?

class A :
{
public:
virtual ~A() {}
};

通过向 A 的析构函数添加虚拟调度(请注意,通过将基析构函数声明为虚拟,它会自动使所有派生类的析构函数变为虚拟,即使未声明为虚拟)。然后对 delete a; 的调用会将析构函数的调用分派(dispatch)到虚拟表中以找到要使用的正确析构函数(在这种情况下为 B 类型)。该析构函数将照常调用父析构函数。整洁,对吧?

可能的问题

正如你所见,这样做你不能破坏任何东西。但是,您的设计中可能存在不同的问题。例如,可能存在“依赖”析构函数的非虚拟调用的错误,您通过使其成为虚拟而暴露出来,请考虑:

int main()
{
B *b = new B;
A *a = b;
delete a;
b->i = 10; //might work without virtual destructor, also undefined behvaiour
}

基本上是对象切片,但由于在此之前您没有虚拟析构函数,因此创建的对象的 B 部分没有被破坏,因此分配给 i 可能会起作用。如果您将析构函数设为虚拟,则它不存在,并且可能会崩溃或执行任何操作(未定义的行为)。

这样的事情可能会发生,并且在复杂的代码中可能很难找到。但是,如果您的析构函数在您将其设为虚拟后导致崩溃,则您可能在某处存在类似这样的错误,并且您一开始就在那里,因为正如我所说,仅将析构函数设为虚拟并不能自行破坏任何东西。

关于c++ - 如果我将一个基类的析构函数从非虚拟更改为虚拟,会发生什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/39073931/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com