为什么我的虚拟析构函数执行了这么多次?
Why does my virtual destructor executes these many times?
我一直在练习继承,我发现从指向继承 class 的基 class 指针调用析构函数会导致奇怪的输出,我发现我的析构函数在其中执行比它应该的更多次。恢复我的代码(编辑:要求更多代码):
#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
电话;每个继承 class (D4,D2,D1) 一个,最后一个用于基础 class (B)。
这些结果应该是正常的吗?我的代码有问题吗?
您提供的代码拆分出以下输出:
f(3) - D2
~D4() destructor
~D2() destructor
~D1() destructor
~B() destructor
您预期有 4 次析构函数调用是正确的。 ~D4()->~D2()->~D1()->~B()
但是从你的输出来看,你实际上是在删除两个 D4
个对象,一个 D1
个对象,另一个 D2
个对象。
更新:
析构函数在
时被调用
- 您对一个对象调用了 delete。
- 超出范围。
现在为了说明我的观点,我将介绍一个自定义范围:
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
您在堆栈上分配了 D2
、D3
和 D4
个对象,在堆上分配了一个 D4
对象。您看到的是 D1
、D2
和 D4
析构函数的输出(您没有在 D3
析构函数中输出任何内容)。
您认为 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
看到这个 live demo,它具有与您显示的相同的析构函数输出。
如果您将输出添加到 D3
的析构函数,这可能会更加明显:
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
我一直在练习继承,我发现从指向继承 class 的基 class 指针调用析构函数会导致奇怪的输出,我发现我的析构函数在其中执行比它应该的更多次。恢复我的代码(编辑:要求更多代码):
#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
电话;每个继承 class (D4,D2,D1) 一个,最后一个用于基础 class (B)。
这些结果应该是正常的吗?我的代码有问题吗?
您提供的代码拆分出以下输出:
f(3) - D2
~D4() destructor
~D2() destructor
~D1() destructor
~B() destructor
您预期有 4 次析构函数调用是正确的。 ~D4()->~D2()->~D1()->~B()
但是从你的输出来看,你实际上是在删除两个 D4
个对象,一个 D1
个对象,另一个 D2
个对象。
更新:
析构函数在
时被调用- 您对一个对象调用了 delete。
- 超出范围。
现在为了说明我的观点,我将介绍一个自定义范围:
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
您在堆栈上分配了 D2
、D3
和 D4
个对象,在堆上分配了一个 D4
对象。您看到的是 D1
、D2
和 D4
析构函数的输出(您没有在 D3
析构函数中输出任何内容)。
您认为 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
看到这个 live demo,它具有与您显示的相同的析构函数输出。
如果您将输出添加到 D3
的析构函数,这可能会更加明显:
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