class Animal { public:void speak() {cout << "Animal.speak()" << endl;} };class Cat :public Animal {void speak() {cout << "Cat.speak()" << endl;} }; void doWork(Animal& animal) {animal.speak(); }void test01() {Animal an;doWork(an);Cat cat;doWork(cat); }
doWork函数使用Animal类来接收子类执行speak(),理想状态下应该是接收什么类,就执行什么类的speak(多态),而实际情况是无论接收哪个子类的对象,都只会执行Animal.doWork(),原因是代码在编译阶段就完成了地址绑定(地址早绑定),Animal animal = cat就决定了animal.speak()是Animal类的speak而不是cat类的speak,而要实现理想效果就需要代码在运行阶段完成地址绑定(地址晚绑定)。解决办法是将父类的speak函数变为虚函数。
virtual void speak() {cout << "Animal.speak()" << endl; }
在这一步后,Animal类中会多出一个名为vfptr的指针,意为虚函数表指针,其指向一个虚函数表,虚函数表内保存着虚函数的信息,借助cl工具可以查看表结构如下:
而Cat类在继承Animal类后,与父类一样,同样也会有一个vfptr的指针,同样指向一个虚函数表,虚函数表内保存着父类虚函数的信息。(未对父类虚函数重写)
而在子类重写父类的虚函数后,会在子类的vftable会将父类的虚函数覆盖,而父类的虚函数表不变。
而此时doWork(cat)输出的就是Cat.speak()了