虚函数 静态绑定 动态绑定
虚函数详解: https://blog.csdn.net/lyztyycode/article/details/81326699
虚函数作用主要是实现了多态机制。多态就是用父类类别的指针指向其子类的实例,然后通过父类的指针调用实际子类的成员函数。这种技术可与让父类的指针有"多种形态"。(这是一种泛型技术。所谓泛型技术,说白了就是试图使用不变的代码来实现可变的算法。比如:模板技术,RTTI技术,虚函数技术,要么是试图做到在编译时决议,要么试图做到运行时决议。)
C++虚函数&静态绑定和动态绑定-vfptr虚函数指针-vftable虚函数表
https://www.bilibili.com/video/BV1MP4y1Y7qQ?spm_id_from=333.851.header_right.history_list.click
判断是不是动态绑定,就看定义为父类的指针 指的函数是不是虚函数,并且改指针指向子类 的函数是否重写(覆盖)
一个类定义了虚函数,对类有什么影响
总结一:如果类里面定义了虚函数,那么编译器需给这个类型产生一个唯一的vftable虚函数表,虚函数表中主要存储的内容就是RTTI(运行时的类型信息)指针和虚函数的地址。当程序运行时,每一张虚函数表都会加载到内存的.rodata区(只读不能写)
总结二:一个类里面定义了虚函数,那么这个类定义的对象,在其运行时,内存中开始部分,多存储一个vfptr虚函数指针,指向相应类型的虚函数表vftable。一个类型定义的n个对象,他们的vfptr指向的都是同一个虚函数表
总结三:一个类里面虚函数的个数,不影响对象内存大小(vfptr),影响的是虚函数表的大小
总结四:如果派生类中的方法,和基类继承来的某个方法,函数名,参数列表,返回值都相同,而且基类的方法是vritual虚函数,那么派生类的这个方法自动处理为虚函数。(覆盖的关系)
静态绑定:
#include <iostream>
using namespace std;
class Base {
public:
int ma;
public:
Base(int data = 10) : ma (data) {}
//非虚函数
void show() {
cout << "Base::show()" << endl;
}
//非虚函数
void show(int data) {
cout << "Base::show(int)" << data << endl;
}
};
class Son : public Base {
public:
int mb;
public:
Son(int data = 100) : mb(data) {}
void show() {
cout << "Son::show()" << endl;
}
};
int main() {
Son s = Son();
Base* p = &s;
p->show(); //Base::show() 静态绑定,编译期绑定,运行父类函数
p->show(1); //Base::show(int)1 静态绑定,编译期绑定,运行父类函数
return 0;
}
动态绑定:
#include <iostream>
using namespace std;
class Base {
public:
int ma;
public:
Base(int data = 10) : ma (data) {}
//虚函数
virtual void show() {
cout << "Base::show()" << endl;
}
//虚函数
virtual void show(int data) {
cout << "Base::show(int)" << data << endl;
}
};
class Son : public Base {
public:
int mb;
public:
Son(int data = 100) : mb(data) {}
//对父类函数进行了重写
//虚函数表放的是不是父类函数的地址,而是重写后的函数地址
void show() {
cout << "Son::show()" << endl;
}
};
int main() {
Son s = Son();
Base* p = &s;
//Base::show() 是一个虚函数 而且子类进行了重写 进行动态绑定
p->show(); //Son::show() 动态绑定,运行时期的绑定,运行子类函数
p->show(1); //Base::show(int)1 静态绑定,编译期的绑定,运行父类函数
return 0;
}
重写(覆盖):
虚函数表中虚函数地址的覆盖
父类base 虚函数表
子类 虚函数表:
重写(覆盖):虚函数表中虚函数地址的覆盖