当前位置: 首页 > 知识库问答 >
问题:

为什么虚拟析构函数的行为方式?

邰昀
2023-03-14

我读到虚拟析构函数必须在具有虚拟方法的类中声明。我只是不明白为什么必须宣布它们是虚拟的。我从下面的例子中知道为什么我们需要虚拟析构函数。我只是想知道为什么编译器不为我们管理虚拟析构函数。关于虚拟析构函数的工作,有什么我需要知道的吗?以下示例显示,如果析构函数未声明为虚拟,则派生类的析构函数不会被调用,这是为什么?

class Base 
{
    // some virtual methods
public:
    Base()
    {std::cout << "Base Constructor\n";}
    ~Base()
    {std::cout << "Base De-structor\n";}

};

class Derived : public Base
{
public:
    Derived()
    {std::cout << "Der constructor\n";}
    ~Derived()
    { std::cout << "Der De-structor\n";}
} ;         
void main()
{

    Base *b = new Derived();
    delete b;
}

共有3个答案

闻人哲茂
2023-03-14

我了解到虚析构函数必须在有虚方法的类中声明。

是的。但这过于简单化了。< br >并不是说具有虚方法的类需要虚析构函数。但是带有虚方法的类的使用方式意味着它通常需要一个虚析构函数。只有通过指向基类的指针删除对象时,才需要虚析构函数。问题是,当一个对象有虚拟方法时,你通常使用一个指向其基类的指针,即使实际的对象略有不同。

我只是不明白为什么必须宣布它们是虚拟的。

并不是说他们必须这样做。如上所述。这是通常使用模式的结果。

我只是想知道为什么编译器不为我们管理虚拟析构函数。

因为并不总是需要。C的精神是你不必为你不需要的东西付钱。如果编译器总是用虚方法给类添加虚析构函数,那么我将不得不为使用虚析构函数付出代价,即使在我可以在代码库中证明我不需要它的情况下。

关于虚拟析构函数的工作,我需要了解一些事情吗?

只是使用它们需要一点成本。

如果析构函数没有声明为虚拟,则不调用派生类的析构函数,这是为什么呢?

这就是为什么我们有虚拟析构函数来导致这种行为。如果需要此行为,则需要添加虚拟析构函数。但有时可能不需要虚拟析构函数,这使得该方法的用户不需要付出代价。

郑博
2023-03-14

我了解到虚析构函数必须在有虚方法的类中声明。

“必须”这个词太强了:“应该”更适合这个建议。

我只是想知道为什么编译器不为我们管理虚拟析构函数。

C设计人员试图避免编译器只在最极端的情况下做您没有要求它做的事情。语言设计者认识到,生成类多态性的决定应由程序设计者决定,因此他们拒绝将此责任重新分配给编译器。

下面的示例显示,如果析构函数没有声明为虚拟,则不会调用派生类的析构函数,这是为什么呢?

因为你的代码是无效的:通过声明派生非虚拟的析构函数,你promise永远不会通过指向 Base 的指针销毁派生;你的主条目打破了这个promise,调用了未定义的行为。

请注意,只需用确切的类型声明< code>b变量,就可以避免与非虚拟析构函数相关的问题(链接到ideone)。然而,这导致了相当不稳定的设计,所以应该避免使用虚函数和非虚析构函数的继承层次结构。

单于帅
2023-03-14

我只是想知道为什么编译器不为我们管理虚拟析构函数。

因为在C中,您为使用的内容付费。默认情况下,拥有虚拟析构函数涉及编译器向类添加虚拟表指针,这会增加其大小。这并不总是可取的。

下面的示例演示,如果未将析构函数声明为 virtual,则不会调用派生类的析构函数,为什么会这样?

该示例对未定义的行为进行了扩展。这简直是违反规则的。并非所有析构函数都被调用的事实只是一种可能的表现形式。它可能会崩溃。

关于虚拟毁灭器的工作,我需要知道什么吗?

对如果要通过指向基类的指针删除对象,则需要它们。否则,这是未定义的行为。

3) 在第一个备选方案(删除对象)中,如果要删除的对象的静态类型与其动态类型不同,则静态类型应为要删除对象的动态类型的基类,静态类型应具有虚拟析构函数或行为未定义。在第二种选择(删除数组)中,如果要删除的对象的动态类型与其静态类型不同,则行为是未定义的。(强调矿井)

 类似资料:
  • 本文向大家介绍请你回答一下为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数?相关面试题,主要包含被问及请你回答一下为什么析构函数必须是虚函数?为什么C++默认的析构函数不是虚函数?时的应答技巧和注意事项,需要的朋友参考一下 将可能会被继承的父类的析构函数设置为虚函数,可以保证当我们new一个子类,然后使用基类指针指向该子类对象,释放基类指针时可以释放掉子类的空间,防止内存泄漏。  

  • 我读过一些文章,正如他们所说,主要的虚拟析构函数用例是: > 派生类可能具有来自堆的动态数据分配,即“拥有”该数据对象。所以,他们需要在析构函数中使用一些删除例程。通过基类指针删除需要在所有派生类中声明析构函数,直到那些具有动态数据分配的析构函数(基类也需要它) 此类具有< code >虚拟方法。但这对我来说不清楚。仅仅通过基类指针调用< code >虚拟方法总是会导致派生实现最多的调用。他们唯一

  • 在C 11中,我们能够声明一个析构函数是自动生成的: 此外,我们可以将析构函数声明为纯虚: 我的问题是:如何将析构函数声明为自动生成和纯虚拟?看起来以下语法不正确: 这一个也不是: 也不是这个: 编辑:关于问题目的的一些澄清。基本上,我希望一个空类是不可实例化的基类,但派生类是可实例化的,那么该类必须有一个纯虚拟析构函数。但另一方面,我不想在.cpp文件中提供定义。因此,我需要某种与等效的机制。我

  • 我想知道为什么我们不应该重写非虚拟函数?

  • 问题内容: 在C ++中,从构造函数内部调用虚拟函数时,它的行为不像虚拟函数。 我认为第一次遇到这种行为的每个人都会感到惊讶,但第二次认为这是有道理的: 只要派生的构造函数没有被执行的对象是 不是 又一个 衍生 实例。 那么如何调用派生函数呢?前提条件还没有建立的机会。例: Java和.NET完全相同,但是他们选择了另一种方式,这可能是 产生最少惊讶原则 的唯一原因吗? 您认为哪个是正确的选择?

  • 在这些关于C 11/14标准的幻灯片中,在幻灯片15中,作者写道,“许多经典的编码规则不再适用于C 11中”。他提出了三个示例的列表,我同意三法则和内存管理。 然而,他的第二个例子是“具有虚拟成员的虚拟析构函数”(仅此而已)。这是什么意思?我知道必须将基类析构函数声明为虚拟,以便调用正确的析构函数,如果我们有类似的东西 这里很好地解释了:什么时候使用虚拟析构函数? 但是,如果您有虚拟成员,现在在C