11. 虚函数

多态:不关心子类对象的具体类型,调用子类对象自己的虚函数。

实现:虚函数。通过父类的指针或引用调用虚函数时才发生动态绑定。

虚表:虚函数构成的数组。

虚表指针:指向数组的指针

虚表指针赋值时机:构造对象时,给本对象赋值为自己的虚表指针。子类构造时,先构造父类,于是先赋值为父类的虚表指针,父类构造完毕后,再赋值为子类的虚表指针。

虚表的创建在编译期就完成了,数据保存在exe中。

简单举例:

 

class B {
public:
	B() {

	}
	virtual void f1() {}
	virtual void f2() {}
	virtual void f3() {}
	virtual void f4() {}
};

class D :public B {
public:
	D() {

	}
	virtual void f1() override {}
	virtual void f2() override {}
};

 

  

 

010 Editor打开磁盘中的exe,选中的一行是虚表,有四个虚函数:

 

vs2019调试状态:

 

内存情况: 

 

 

整个过程:

一.编译期:

1.编译器创建父类B的虚表

B::vftable[4] = {B::f1, B::f2, B::f3, B::f4};

  

2.编译器拷贝父类B的虚表给子类

D::vftable[4] = {B::f1, B::f2, B::f3, B::f4};

  

3.编译器替换子类D重写的部分,未重写则继续用父类的

D::vftable[4] = {D::f1, D::f2, B::f3, B::f4};

  

二.运行期:

书写B *p = new D;时,发生如下事情:

1.构造父类B

__vfptr = B::vftable;

  

2.构造子类D

__vfptr = D::vftable;

  

调用虚函数p->f1();时,通过虚表指针,以数组下标寻址的方式获取数组第一项,即虚函数f1的地址,然后调用:

(p->(__vfptr[0])) ();

  

 

 

猜你喜欢

转载自www.cnblogs.com/Nutshelln/p/12921282.html