请仔细阅读以下代码:
#include "stdafx.h"
#include <iostream>
#include <conio.h>
using namespace std;
class ClassA
{
protected:
int width, height;
public:
void set_values(int x, int y)
{
width = x;
height = y;
}
virtual int area()
{
return 100;
}
~ClassA()
{
cout << "base class destructor called" << endl;
}
};
class ClassB : public ClassA
{
public :
int area()
{
return (width * height);
}
~ClassB()
{
cout << "derived class destructor called" << endl;
}
};
int main()
{
ClassA *Ptr = new ClassB;
Ptr->set_values(10, 20);
cout << Ptr->area() << endl;
delete Ptr;
return 0;
}
在上面的代码中,指针包含派生类对象的地址,因此当我删除指针时它应该调用派生类析构函数和基类析构函数,但是为什么它只调用基类析构函数。如果我把基类析构函数作为虚拟,那么它调用派生类和基类析构函数为什么?在虚函数的情况下,基类和派生类都具有相同的函数名,因此编译器解析派生类中派生最多的那个,但是这里的析构函数将不具有相同的名称,然后编译器如何解析它必须调用的那个在运行期间。请解释我如何
答案 0 :(得分:3)
您应该创建基类virtual
的析构函数,以使多态破坏正常工作:
class ClassA
{
// ...
virtual ~ClassA()
// ^^^^^^^
// Add this!
{
cout << "base class destructor called" << endl;
}
};
如果您不这样做,则在执行delete Ptr
时会收到未定义的行为。
如果我将基类析构函数设为virtual,那么它调用派生类和基类析构函数为什么?
这是常规对象销毁序列的一部分。当你销毁一个对象时,首先调用该对象类的析构函数,然后调用该对象的所有非静态类成员的析构函数(按声明的相反顺序),然后是所有基类的析构函数< /强>
因此,虚拟分派在此处正确执行(当然,如果你创建基类析构函数virtual
),从某种意义上说,被调用的第一个析构函数是实际运行时类型的析构函数你的对象(ClassB
)。之后,调用基类ClassA
的析构函数以及正常销毁过程的一部分。
但是这里的析构函数不会有相同的名称,那么编译器如何解析它在运行时必须调用的那个
析构函数是特殊成员函数。每个类只能有一个析构函数,因此它们的名称(必须与类的名称相同,前缀为~
字符)无关紧要。编译器知道哪个函数是析构函数。
答案 1 :(得分:2)
因为你的Base类析构函数应该是virtual
。
答案 2 :(得分:0)
这实际上是未定义的行为,因为~ClassA()
不是virtual
,所以任何事情都可能发生。
ClassA *Ptr = new ClassB;
///....
delete Ptr;
答案 3 :(得分:0)
您需要将析构函数标记为虚拟。否则,编译器不知道调用派生最多的析构函数。
virtual ~ClassA()
{
cout << "base class destructor called" << endl;
}