这已经在我的官方笔记中提供了,但是我发现了一个错误。在我把它交给我的教练之前,我只是想在这里和我所有的兄弟们——你们——确认一下。
#include <iostream.h>
class Base {
public:
virtual void display() { cout << "Base class" << endl; }
};
class Derived: public Base {
// Nothing here
};
void main()
{
Base * ptr;
// Calls Base::display ( )
ptr = new Base ;
ptr ->display();
delete ptr ;
// Calls Base::display ( ) again
ptr = new Derived ;
ptr ->display();
delete ptr ;
}
输出为:
Base class
Base class
我认为问题出在main函数的最后一行。我的意思是,由于析构函数不是虚拟的,我不认为你可以使用基类类型的指针删除派生类类型的动态分配实例。你怎么看?
我的意思是,由于析构函数不是虚拟的,我认为你不能使用基类类型的指针删除派生类类型的动态分配实例。你怎么想呢?
您可以在此处和此处看到这是未定义的行为。
如果基类没有虚析构函数,则此类代码的行为只是未定义的。
从C标准:
5.3.5删除
3在第一种选择(删除对象)中,如果操作数的静态类型与其动态类型不同,则静态类型应是操作数动态类型的基类,并且静态类型应具有虚拟析构函数或行为未定义。
当一个函数被定义为虚拟时,编译器将使用指向使用动态绑定的基的指针调用该函数,即对实际函数的调用将通过类vTable找到该函数的相关实现。如果一个函数没有被定义为虚拟,那么编译器生成的代码将使用静态绑定,即编译器将简单地调用它知道的函数。换句话说,如果你在基类指针上调用一个指向派生类的非虚函数,那么编译器将生成调用基类实现的代码。
现在,析构函数行为只是上述一般行为的一个私人案例。由于没有析构函数实现,编译器将为您生成一个默认的非虚析构函数,使用基类指针销毁对象只会调用基类析构函数。您可以通过显式定义基类和派生类的非虚析构函数轻松重现此行为,并使用调试器查看被调用的是基类版本。