首页 > 代码库 > C++学习笔记27,虚函数的工作原理
C++学习笔记27,虚函数的工作原理
C++规定了虚函数的行为,但是将实现交给了编译器的作者.
通常,编译器处理虚函数的方法是给每一个对象添加一个隐藏成员.隐藏成员中保存了一个指向函数地址数组的指针.
这个数组称为虚函数表(virtual function table,vtbl).虚函数表中存储了为类对象进行声明的虚函数的地址.
例如:基类对象包含一个指针,该指针指向基类的虚函数表.
派生类对象包含一个指针,该指针指向一个独立的虚函数表.如果派生类提供了虚函数的新定义,虚函数表将保存新的函数地址.
如果派生类没有重新定义虚函数,虚函数表将保存原版本的地址.如果派生类定义了新的虚函数,则将该函数地址也添加到虚函数表中!
看下面的例子:
#include <iostream> #include <string> using namespace std; class Animal{ protected: string name; public: Animal(const string &s):name(s){ } virtual ~Animal(){ } //非虚函数 void eat()const{ cout<<"Animal eat!"<<endl; } //不被重写的虚函数 virtual void run()const{ cout<<"Animal run!"<<endl; } //会被重写的虚函数 virtual void speak()const{ cout<<"I'm a Animal!"<<endl; } }; class Dog:public Animal{ public: Dog(const string &s):Animal(s){ } virtual ~Dog(){ } //新定义的函数eat,将掩盖旧的版本,非重写(重写是指重写virtual函数) void eat()const{ cout<<"Dog eat!"<<endl; } //重写speak() virtual void speak()const override{ cout<<"This's a Dog!"<<endl; } //新的虚函数 virtual void fun1()const{ } }; int main(){ Animal a("AnimalOne"); Dog d1("DogOne"); Animal *p1=&a; Animal *p2=&d1; p1->speak(); p2->speak(); p1->eat(); p2->eat(); //call Animal::eat() p1->run(); p2->run(); //call Animal::run() Animal &r1=a; Animal &r2=d1; r1.speak(); r2.speak(); r1.eat(); r2.eat(); r1.run(); r2.run(); return 0; }
注意eat不是虚函数,不会保存在虚函数表中
//Animal虚函数表 地址:1000
Animal::run() 4000
Animal::speak() 5000
Dog虚函数表 地址:2000
Dog::run() 4000(没有被重写,保存原地址)
Dog::speak() 7000(重写了,保存新地址)
Dog::fun() 8000(新的虚函数,保存地址)
详细分析下面的代码
p1->speak(); //找到Animal中speak的地址,5000
p2->speak(); //找到Dog中speak的地址,7000,执行代码Dog::speak();
p1->run(); //同上
p2->run(); //
这样,对于虚函数表就有了一个初步的了解了!
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。