c++ 虚函数

一、动态捆绑与虚函数

      把函数体与函数调用相联系称为捆绑,当捆绑在程序允许之前(由编译器和连接器)完成时,这称为早捆绑。而在运行时根据对象的类型进行的捆绑被称为晚捆绑,又称为动态捆绑,或运行时捆绑。当一个语言实现晚捆绑时,必须有某种机制来确定运行时对象的类型并调用合适的成员函数,对于一种编译语言,编译器并不知道实际的对象模型,但它插入能找到和调用正确函数体的代码。

       对于特定的函数,为了实现晚捆绑,c++要求在基类中声明这个函数时使用virtual关键字,晚捆绑只对virtual函数起作用,而且只在使用virtual函数的基类地址时发生。注意:仅仅在声明的时候需要使用关键字virtual,定义时并不需要,如果一个函数在基类被声明为virtual,那么在所有的派生类中它都是virtual的。

二、晚捆绑的实现

       晚捆绑如何发生?所有的工作都由编译器在幕后完成。当告诉编译器要晚捆绑时(通过创建虚函数来告诉),编译器安装必要的晚捆绑机制。

编译器对每个包含虚函数的类创建一个表(VTABLE),在VTABLE中,编译器放置特定类的虚函数的地址。在每个带有虚函数的类中,编译器秘密地放置一个指针,成为VPTR。当通过基类指针做虚函数引用时(即多态调用),编译器静态地插入能取得这个VPTR并在VTABLE表中查找函数地址的代码,这样就能调用正确的函数并引起晚捆绑的发生。

     为每个类设置VTABLE,初始化VPTR,为函数调用插入代码,所有这些都是自动发生的。利用虚函数,即使在编译器还不知道这个对象的特定类型的情况下,也能调用这个对象中正确的函数。

    每当创建一个包含有虚函数的类或从包含有虚函数的类派生一个类时,编译器就位这个类创建一个唯一的VTABLE。在这个表中,编译器防止了在这个类中或在它的基类中所有已声明为virtual的函数的地址。如果在这个派生类中没有对在基类中声明为virtual的函数进行重新定义,编译器就使用基类的这个虚函数地址。然后编译器在这个类中放置VPTR,当使用简单继承时,对于每个对象只有一个VPTR,VPTR必须被初始化为指向相应的VTABLE的起始地址(在构造函数中发生)。

 

你可能感兴趣的:(c++ 虚函数)