求编译时不存在的Virtual Function调用示例(优先C++/Java)
维基百科提到“Virtual functions允许程序调用在代码编译时不一定存在的方法”,下面用C++和Java的示例来具体说明:
C++ 虚函数示例
C++中需要显式用virtual关键字声明虚函数,通过基类指针/引用实现动态绑定:
#include <iostream> using namespace std; // 基类 class Animal { public: // 声明虚函数 virtual void makeSound() { cout << "动物发出声音" << endl; } }; // 派生类:狗 class Dog : public Animal { public: // 重写基类虚函数,override关键字用于检查重写是否正确 void makeSound() override { cout << "汪汪汪" << endl; } }; // 派生类:猫 class Cat : public Animal { public: void makeSound() override { cout << "喵喵喵" << endl; } }; int main() { Animal* animal1 = new Dog(); Animal* animal2 = new Cat(); // 编译时仅知道变量是Animal*类型,无法确定实际调用的方法 // 运行时通过虚函数表(vtable)找到对应对象的方法 animal1->makeSound(); // 输出:汪汪汪 animal2->makeSound(); // 输出:喵喵喵 delete animal1; delete animal2; return 0; }
关键说明
编译阶段,编译器无法预知animal1和animal2实际指向的是Dog还是Cat对象,因此不能直接确定要调用哪个makeSound方法。程序运行时,每个包含虚函数的类都会生成一张虚函数表,对象会持有指向该表的指针,通过这个指针找到当前对象实际类型对应的方法实现。
如果后续新增Bird类并继承Animal重写makeSound,原main代码无需修改就能正确调用Bird的方法——这就是“调用编译时不一定存在的方法”的核心体现。
Java 虚函数示例
Java中默认非静态、非final、非private、非static的方法都是虚函数,自动支持动态绑定:
class Animal { void makeSound() { System.out.println("动物发出声音"); } } class Dog extends Animal { @Override void makeSound() { System.out.println("汪汪汪"); } } class Cat extends Animal { @Override void makeSound() { System.out.println("喵喵喵"); } } public class Main { public static void main(String[] args) { Animal animal1 = new Dog(); Animal animal2 = new Cat(); // 编译时仅知道变量是Animal类型,运行时根据实际对象类型绑定方法 animal1.makeSound(); // 输出:汪汪汪 animal2.makeSound(); // 输出:喵喵喵 } }
关键说明
Java的方法调用默认采用动态绑定机制,编译阶段只检查变量的编译类型(Animal)是否有对应的方法,运行时才根据对象的实际类型(Dog/Cat)调用对应的重写方法。即使后续新增任意Animal的派生类,原代码无需修改即可适配新类的方法调用,完美契合维基百科的描述。
内容的提问来源于stack exchange,提问作者Hank
相关产品推荐
相关产品推荐

