为什么我的虚拟破坏者多次执行这些执行

Why does my virtual destructor executes these many times?

本文关键字:执行 我的 虚拟 破坏者 为什么      更新时间:2023-10-16

我一直在继承练习,我发现从基类指针指向继承类的deStuructor,结果为一个奇怪的输出,我发现我的destructor执行更多时间比应该。恢复我的代码(编辑:要求更多代码(:

#include <iostream>
using namespace std;
class B{
public:
    virtual void f(){cout << "f() - B" << endl;}
    virtual void g(){cout << "g() - B" << endl;}
    virtual void h() = 0;
    virtual ~B(){cout << "~B() destructor" << endl;}
protected:
    int b;
};
class D1: virtual public B{
public:
    void f(){cout << "f() - D1" << endl;}
    virtual void g(){cout << "g() - D1" << endl;}
    virtual ~D1(){cout << "~D1() destructor" << endl;}
protected:
    int d1;
};
class D2: virtual public B{
public:
    void f(int i){cout << "f(" << i << ") - D2" << endl;}
    virtual void h(){cout << "h() - D2" << endl;}
    virtual ~D2(){cout << "~D2() destructor" << endl;}
protected:
    int d2;
};
class D3: public D1{
public:
    void g(){cout << "g() - D3" << endl;}
    void h(){cout << "h() - D3" << endl;}
private:
    int d3;
};
class D4: public D1, public D2{
public:
    using D1::f; using D2::f;
    virtual ~D4(){cout << "~D4() destructor" << endl;}
private:
    int d4;
};
void f(B& b){
   cout << "f() out " << endl;
   b.f();
   b.g();
   b.h();
};
int main()
{
    B *pB;
    D2 d2;
    D3 d3;
    D4 d4;
    f(d2);
    f(d3);
    f(d4);
    d4.D1::f();
    d4.f(5);
    d4.f(3.7);
    d4.g();
    d4.h();
    pB = new D4;
    pB -> f();
    dynamic_cast<D4*>(pB)->f(3);
    pB -> g();
    pB -> h();
    delete pB;
}

最终输出是:

//Other tests
.
.
.
f(3) - D2
~D4() destructor
~D2() destructor
~D1() destructor
~B()  destructor
~D4() destructor
~D2() destructor
~D1() destructor
~B()  destructor
~D1() destructor
~B()  destructor
~D2() destructor
~B()  destructor

创建PB指针;指向新的D4对象;向D4 F((方法和删除呼叫的明确调用。我期望只有四个destructor呼叫;每个继承的类( d4,d2,d1 (,最后一个用于基类( b (。

这些结果应该正常吗?我的代码有问题吗?

您提供的代码分解以下输出:

f(3) - D2
~D4() destructor
~D2() destructor
~D1() destructor
~B() destructor

实时演示

您可以期待4个Destructor呼叫。~D4()->~D2()->~D1()->~B()

但是从输出来判断,您实际上删除了两个D4对象,一个D1对象和另一个D2对象。

更新:

时称为击曲率
  1. 您在对象上调用删除。
  2. 它不在范围内。

现在说明我的观点,我将介绍一个自定义范围:

int main()
{
    B *pB;
    { // custom scope
        D2 d2;
        D3 d3;
        D4 d4;
        f(d2);
        f(d3);
        f(d4);
        d4.D1::f();
        d4.f(5);
        d4.f(3.7);
        d4.g();
        d4.h();
        pB = new D4;
        pB->f();
        dynamic_cast<D4*>(pB)->f(3);
        pB->g();
        pB->h();
    }
    delete pB;
}

调用此功能将打印以下输出:

//function calls
~D4() destructor <-- inside custom scope
~D2() destructor <-- inside custom scope
~D1() destructor <-- inside custom scope
~B() destructor  <-- inside custom scope
~D1() destructor <-- inside custom scope
~B() destructor  <-- inside custom scope
~D2() destructor <-- inside custom scope
~B() destructor  <-- inside custom scope
~D4() destructor <-- outside custom scope
~D2() destructor <-- outside custom scope
~D1() destructor <-- outside custom scope
~B() destructor  <-- outside custom scope

您的 D2D3D4对象分配在堆栈上,而分配在堆上的 D4对象。您正在看到D1D2D4驱动器的输出(您没有在D3 Destructor中输出任何内容(。

您认为delete是灾难仪被调用的唯一方法吗?事实并非如此,但这似乎就是您在想的。您将为您创建的所有4个对象获取破坏者的输出消息。堆栈上的对象在main()的末端出现范围时会自动破坏(以相反的创建顺序(。当您在其上明确调用delete时,堆上的对象会破坏:

// when you delete pB...
~D4() destructor
~D2() destructor
~D1() destructor
~B()  destructor
// when d4 goes out of scope...
~D4() destructor
~D2() destructor
~D1() destructor
~B()  destructor
// when d3 goes out of scope...
~D1() destructor
~B()  destructor
// when d2 goes out of scope...
~D2() destructor
~B()  destructor

请参阅此实时演示,它具有与您显示的相同的驱动器输出。

如果您将输出添加到D3的destructor:

class D3: public D1{
public:
    void g(){cout << "g() - D3" << endl;}
    void h(){cout << "h() - D3" << endl;}
    virtual ~D3(){cout << "~D3() destructor" << endl;} // <-- add this!
private:
    int d3;
};

// when d3 goes out of scope...
~D3() destructor <-- this message now appears
~D1() destructor
~B()  destructor