2017-02-22 90 views
0

只是出于好奇,我试图做下面的例子,看看编译器是否给我一个警告,所以不要调用一个以堆栈溢出结束的无限循环。我想也许有一种不同于只调用普通函数或方法的行为。但事实并非如此。有没有特别的解释呢,还是只是作为正常的函数调用来处理,因为我通过使用this运算符显式调用基类析构函数?编译器如何处理派生析构函数中的基类析构函数调用?

例子:

class A { 
    virtual ~A(); 
}; 

class B : A { 
    virtual ~B() { this->~A(); } 
}; 
+2

'virtual void〜A();' - 这不应该编译,析构函数不返回任何东西,并且普通的方法名称不能包含tilda。 – yeputons

+0

@yeputons right,sry,is typo –

+4

它会通过调用'〜A()'两次导致未定义的行为(因为有一个隐含的调用,一旦'〜B()'的主体退出) –

回答

2

@ M.M的评论击中它。你正在调用析构函数两次。这是未定义的行为,可能会发生任何事情,包括您观察到的行为。

(在现实中,这些析构函数调用的最有可能的一个修改对象的vptr的,这意味着随后的析构函数调用不再去最派生的对象。但是,这只是一个猜测。)

正确的事要做的是不要手动调用析构函数。

+1

C++ 14 [class.dtor]/15是具体说第二个析构函数调用的子句是UB,对于具有非平凡析构函数的类(这是因为'virtual'使它不平凡) –

0

调用派生类虚拟析构函数会导致调用基类析构函数。但不反之亦然。

1

派生类中的虚拟析构函数将总是首先调用父类析构函数,按递归顺序调用最“祖先”基类的析构函数,然后调用第二个“祖先”等等。想象一下,Child从继承自GrandParent的Parent继承。 Child类的析构函数实际上会调用GrandParent的析构函数,然后调用Parent的析构函数,然后调用Child的析构函数。

事实上,您的派生类构造函数也会以相同的递归顺序调用它们的父类构造函数。你必须想象派生类,比如“图层蛋糕”:每个继承实例都会为你的对象添加一个图层。所以Child类有3层{GrandParent,Parent,Child},每层的构造/销毁都由相应的类来处理。

你试图尝试调用父析构函数两次,这是一个坏主意。一般情况下,您不必显式调用析构函数,除非您超载了new运算符。看到这个答案的更多细节:Is calling destructor manually always a sign of bad design?

相关问题