看看这个:
#include <iostream>
class Base
{
public:
void nonvirtualmethod()
{ std::cout << "Base nonvirtualmethod" << std::endl; }
virtual void virtualmethod()
{ std::cout << "Base virtualmethod" << std::endl; }
};
class Derived: public Base
{
public:
void nonvirtualmethod()
{ std::cout << "Derived nonvirtualmethod" << std::endl; }
virtual void virtualmethod()
{ std::cout << "Derived virtualmethod" << std::endl; }
};
int main()
{
Derived d;
Derived* pd = &d;
Base* pb = &d; //< NOTE: both pd and pb point to the same object
pd->nonvirtualmethod();
pb->nonvirtualmethod();
pd->virtualmethod();
pb->virtualmethod();
}
我给你以下输出:
Derived nonvirtualmethod
Base nonvirtualmethod
Derived virtualmethod
Derived virtualmethod //< invoked by a Base*
pb
这是因为指针的静态类型 ( Base*
) 和它指向的动态类型( )之间存在差异Derived
。虚拟方法和普通方法的区别在于,非虚拟方法遵循静态类型映射(因此Base
指针调用Base::
方法),而虚拟方法遵循运行时类型链,因此如果 aBase*
指向 a Derived
,则该Derived
方法将被调用.
从这个意义上说,析构函数没有什么特别的:如果它不是虚拟的,Base
指针将不会调用Derived
它,因此你会得到一个半毁坏的对象,它会被返回给内存存储。
这是 UB(而不是简单地否认)的原因是因为“内存存储”不是由语言本身管理的,而是从程序所在的平台管理的:崩溃很可能取决于缺少该Derived
部分(仍然存在)将导致操作系统尝试释放具有错误起始地址的内存块。