首页IT科技虚函数是实现动态联编的充分必要条件(虚函数 静态绑定 动态绑定)

虚函数是实现动态联编的充分必要条件(虚函数 静态绑定 动态绑定)

时间2025-06-20 01:45:43分类IT科技浏览4306
导读:代码1 class...

代码1

class Base { public: Base(int data=10):ma(data){ cout<<"Base()"<<endl; } void show(){cout<<"Base Show()"<<endl;} void show(int){cout<<"Base Show(int)"<<endl;} ~Base(){cout<<"~Base()"<<endl;} protected: int ma; }; class Derive : public Base { public: Derive(int data=20):Base(data),mb(data){ cout<<"Derive()"<<endl; } void show(){cout<<"Derive Show()"<<endl;} ~Derive(){cout<<"~Derive()"<<endl;} private: int mb; }; int main(){ Derive d(20); Base *pb=&d; pb->show(); //静态绑定(编译期间绑定) pb->show(100) //静态绑定(编译期间绑定) cout<<sizeof(Base)<<endl; // 4 字节 cout<<sizeof(Derive)<<endl; // 8字节 cout<<typeid(pb).name()<<endl; // clas Base * cout<<typeid(*pb).name()<<endl; // class Base return 0; }

代码2

class Base { public: Base(int data=10):ma(data){ cout<<"Base()"<<endl; } //虚函数 virtual void show(){cout<<"Base Show()"<<endl;} //虚函数 virtual void show(int){cout<<"Base Show(int)"<<endl;} ~Base(){cout<<"~Base()"<<endl;} protected: int ma; }; class Derive : public Base { public: Derive(int data=20):Base(data),mb(data){ cout<<"Derive()"<<endl; } void show(){cout<<"Derive Show()"<<endl;} ~Derive(){cout<<"~Derive()"<<endl;} private: int mb; }; int main(){ Derive d(20); Base *pb=&d; pb->show(); //动态绑定(运行期间绑定) pb->show(100) //动态绑定(运行期间绑定) ) cout<<sizeof(Base)<<endl; // 12 字节 cout<<sizeof(Derive)<<endl; // 16 字节 cout<<typeid(pb).name()<<endl; // cout<<typeid(*pb).name()<<endl; // return 0; } //在上面的代码中,如果一个类中定义了虚函数,编译器会做什么?? //1:一个类里面定义了虚函数,那么编译阶段,编译器给这个类会产生一个唯一的vftable虚函数表, // 虚函数表中主要存储的内容就是RTTI和虚函数地址,如下图 //2:当程序运行时,每一张(程序中的可能有很多类都有虚函数,每一个类都会对应一个虚函数表)虚函数表都会加载到内存的.rodata区 // 一个类里面定义了虚函数,那么这个类定义的对象,其运行时,在内存中开始部分,多存储一个vfptr虚函数指针,指向相应 // 类型的虚函数表vftable, 一个类型定义的n个对象,指向同一张表 //3:一个类里面虚函数的个数,不影响对象内存大小(vfptr)            ,影响的是虚函数表的大小 //4:如果派生类中的方法,和基类继承来的某个方法,返回值,函数名,参数列表都相同,而且基类的方法是virtual虚函数 // 那么派生类的这个方法,自动处理成虚函数

虚函数 静态绑定 动态绑定

虚函数 静态绑定 动态绑定

在上面代码2中,Base 中void show()和 void show(int) 为虚函数, 在Derive 中有返回值,函数名,参数列表都

相同的 show()方法,这个时候 我叫 重写(或覆盖 即要返回值,函数名,参数列表 都相同),这个Derive中的void show()方法也会处理成虚函数.所以有

下图 Derive中的show()方法地址替换掉继承来的Base的show()函数地址 ,同时我们也可以看到Base中的 void show(int) 并没有被覆盖

虚函数 静态绑定 动态绑定

覆盖:基类和派生类的方法,返回值,函数名以及参数列表都相同,而且基类的方法是虚函数,那么派生类的方法就自动处理成虚函数,他们之前成为覆盖关系.

所以根据上图,我们说 覆盖 其实是指虚函数表中函数地址的覆盖

代码2中的这段代码 Base *pb=&d; pb->show(); //动态绑定(运行期间绑定) pb->show(100) //动态绑定(运行期间绑定) ) pb->show() pb是Base类型,所以编译器会去Base中查看void show()函数情况 如果是普通函数,那么静态绑定(编译期绑定),但是发现是 void show()函数是个虚函数就进行动态绑定了 同理 pb->show(100)发现Base中的void show(int )也是个虚函数,所以执行动态绑定(运行期绑定). 但是 这两个函数在Derive虚函数表中的区别就是,void show()被Derive覆盖掉了,即虚函数表中的地址被覆盖了 而void show(int) 为被覆盖,所以虚函数表中的 地址仍然是Base的void show(int)的地址 ---------------------------------------- cout<<sizeof(Base)<<endl; // 4 +8 =12 字节 Base中又多了一个虚函数表指针 cout<<sizeof(Derive)<<endl; // 8+8 =16 字节 Derive 多了一个虚函数表指针 ------------------------------------------------------ cout<<typeid(pb).name()<<endl; // Base * cout<<typeid(*pb).name()<<endl; // 关于这句代码typeid(*pb).name(),即打印指针指向对象的类型, 先看pb是Base类型,再看有没有虚函数 1:如果没有虚函数,那么*pb 识别的是编译时期的类型,即 Base class 2:如果有虚函数,那么 *pb 识别的是运行时的类型,即RTTI类型,RTTI是存储在虚函数表中,所以要在运行期识别 即 pb->d(vfptr)->Derive vftable -> Class Derive

虚函数 静态绑定 动态绑定

创心域SEO版权声明:以上内容作者已申请原创保护,未经允许不得转载,侵权必究!授权事宜、对本内容有异议或投诉,敬请联系网站管理员,我们将尽快回复您,谢谢合作!

展开全文READ MORE
企业网站推广(如何选择推广方式,提升企业网站的曝光率?) go python 爬虫(go爬虫+WordPress每月躺赚上千元(合法合规实战))