详解虚函数的实现过程之单继承(2)

从汇编分析一下下面的多态模拟结构
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
利用 父类指针指向子类的特性,可以间接调用各子类中的虚函数。
虽然指针类型为父类,但由于虚表的排列顺序是按虚函数在类继承层次中首次声明的顺序依次排列的,因此,只要继承了父类,其派生类的虚表中的父类部分的排列就与父类的一致,子类新定义的虚函数将会按照声明顺序紧跟其后。

我们给Speak函数传递任何一个基于CPerson的派生对象地址都能正确调用虚函数ShowSpeak,那么当我们调用虚函数时,它是如何实现调用的呢?请看下面分析
在这里插入图片描述
分析如下:

地址401108的eax是this指针,即对象的地址,
然后40110B是取了this指针所指的地方的值(也就是虚表指针的值),即虚表的地址传给edx,
最后edx+4也就是虚表里面第二个元素的地址,然后[edx+4]即第二个元素的值(因为数组元素是一个函数指针),也就是第二个虚函数ShowSpeak的地址。

由于虚函数采用间接调用机制,因此在使用父类指针pPerson调用虚函数时,没有依照其作用域调用CPerson类中定义的成员函数ShowSpeak

当父类中定义有虚函数时,将会产生虚表。当父类的派生类产生对象时,将会调用子类的构造函数前优先调用父类构造函数,并以子类对象的首地址作为this指针传给父类构造函数。

在父类构造函数中,会先初始化子类虚表指针为父类的虚表首地址。此时,如果在父类构造函数中调用虚函数,虽然虚表指针属于子类对象,但指向的地址却是父类的虚表首地址,这是可判断虚表所属作用域相同,于是转成直接调用,从而造成构造函数内的虚函数失效

在这里插入图片描述
在这里插入图片描述
这里也就是在构造函数里面调用了 虚函数,会出现 多态的失效。

父类构造函数会在子类构造函数之前运行,在执行父类构造函数时将虚表指针修改为当前类的虚表指针,即父类的虚表指针,导致虚函数特性失效。

如果父类构造函数内部存在虚函数调用的话,这样的顺序能防止在子类中构造父类时,父类会根据虚表错误地调用子类的成员函数。

大家心里会不会出现一个疑问:直接让编译器把构造函数或析构函数中的虚函数调用修改为直接调用方式,不就可以避免这类问题了吗????
但是大家别忘了,程序员仍然可以自己编写其它成员函数间接调用本类中声明的其它虚函数。

举个例子:
假设类A中定义了成员函数f1()和虚函数f2(),而且类B继承类A并重写f2()。根据前面的讲解我们可以知道,在子类B的构造函数执行前会调用父类A的构造函数,此时如果在类A的构造函数中调用了f1(),显然不会构成多态,编译器会直接调用f1()的代码,但是,如果在f1()中调用了f2(),此时就会产生间接调用的指令,形成多态。如果类B的对象的虚表指针没有更换为类A的虚表指针,就会导致在访问类B 的虚表后调用到类B中的f2()函数,而此时类B的对象尚未完成构造,其数据成员时不确定的,这时在f2()中引用类B的对象中的数据成员是很危险的。

同理,在析构类B的对象时,会先执行类B的析构函数,然后执行类A 的析构函数。如果在类A的析构函数中调用f1(),显然不能构成多态,编译器同样会产生直接调用f1()的代码。但是,如果f1()中又调用了f2(),此时会构成多态,如果这个对象的虚表指针没有更换为类A 的虚表指针,同样也会导致访问虚表并调用类B中的f2()。但是,此时B类对象已经执行过析构函数了,所以B类中定义的数据已经不可靠了,对其进行操作是很危险的

这也就是我们经常说的在构造函数和析构函数里面会发生虚表覆盖

析构总结:
首先调用自身的析构函数,然后调用成员对象的析构函数,最后调用父类的析构函数。
在对象析构时,首先设置虚表指针为自身虚表,再调用自身的析构函数。
如果有成员对象,则按申明顺序以 倒序方式依次调用成员对象的析构函数。
最后,调用父类析构函数。在调用父类析构函数的时候,会设置虚表指针为父类自身的虚表。

构造函数和析构函数调用流程如下:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
分析如下:
首先调用了父类的构造函数,然后设置虚表指针为当前类的虚表首地址。而析构函数中的顺序却与构造函数相反,首先设置虚表指针为当前类的虚表首地址,然后调用父类的析构函数。其构造和析构过程如下:
构造:基类------>基类的派生类------->…………------->当前类
析构:当前类------>基类的派生类------->…………------->基类
虚函数系列:
详解虚函数的实现过程之初探虚表(1)
详解虚函数的实现过程之单继承(2)
详解虚函数的实现过程之多重继承(3)
详解虚函数的实现过程之虚基类(4)
详解虚函数的实现过程之菱形继承(5)

猜你喜欢

转载自blog.csdn.net/CSNN2019/article/details/111350692