无论何时,一个类定义了一个虚拟方法,大多数编译器向类指定一个指向虚拟方法表(VMT或Vtable)的(虚拟)函数的指针数组添加一个隐藏的成员变量。这些指针在运行时用于适当的函数调用,因为在编译时它可能还不知道是否要调用基函数或者是从继承基类的类实现的派生类。
虚拟方法表解决方案在C++及其相关语言(如D和C#)中尤为常见。将对象的编程接口从实现分离出来的语言,像Visual Basic和 Delphi, 也可以使用虚拟表实现。因为它允许对象使用不同的实现,只需要使用一组不同的方法指针。
这边涉及到继承(多态)的知识点
举个栗子:
DerivedC c2=new DerivedC();
BaseClass a1= c2; //BaseClass 基类,DerivedC是继承自BaseClass的子类
a1.play(); //play()在BaseClass,DerivedC中均有定义,即子类覆写了该方法
分析:
- 为什么子类的类型的对象实例可以覆给父类引用?
自动实现向上转型。通过该语句,编译器自动将子类实例向上移动,成为通用类型BaseClass; - a.play()将执行子类还是父类定义的方法?
子类的。在运行时期,将根据a这个对象引用实际的类型来获取对应的方法。所以才有多态性。一个基类的对象引用,被赋予不同的子类对象引用,执行该方法时,将表现出不同的行为。
在a1=c2的时候,仍然是存在两个句柄,a1和c2,但是a1和c2拥有同一块数据内存块和不同的函数表。
那么 :父类 对象 = new 子类()的意义就是为了实现多态(以不变应万变),其中,这句话中的父类就是为了方便找到偏移量,父类决定偏移量,子类决定方法实现,子类与父类中相同的方法与属性在各自的虚拟方