为了账号安全,请及时绑定邮箱和手机立即绑定

关于虚函数我自己的一点理论理解,不知道对不对?大家讨论一下,看我的理解有没有偏差

当类中没有虚函数的时候:

       我们通过类的对象访问其数据成员,访问其成员函数;前面已经知道,实例化对象时,只有数据成员的大小,这说明类的成员函数是统一放在内存代码区的,并且有自己的类名称空间作为限制,只能自己实例化的对象访问;所以我们通过对象访问数据成员,是直接在对象的内存块中偏移得到;而通过对象访问成员函数,则是要到代码区才能访问到;

当父类与子类之间有重名函数时:

(1)通过子类对象访问父类该重名函数(于是有了隐藏):

        父类与子类有重名函数时,这时出现了隐藏,即子类是继承了父类的该重名函数的,但是将其隐藏了。通过子类对象访问该函数时,访问的是子类自己的该函数,如果想要访问父类的该函数,则要在函数前面加上父类的名称空间限定;代码示例如下:父类Person和子类Worker,都有一个同名函数name();通过子类对象worker调用父类该函数时,worker.Person::name();

(2)通过父类指针指向子类对象,并访问子类重名函数(于是有了虚函数):

        父类指针指向子类对象时,父类指针只能访问子类对象的数据成员(部分,继承自父类的),和访问父类在代码区的自己的成员函数;此时,如果想要通过父类指针访问到子类对象的成员函数(即通过父类指针调用子类的析构函数或者普通重名函数),就要将该重名函数设定为虚函数,然后将虚函数地址放进该类的虚函数表中(于是有了覆盖,即在子类虚函数表中用子类虚函数地址覆盖掉父类虚函数地址),而对象又多了个数据成员(虚函数表指针),且在对象内存块首位;这样当我们用父类指针指向子类对象,且调用子类重名虚函数时,就要先在虚函数表中查找,如果找到,就执行;即调用成员函数时,有虚函数表先在虚函数表中查找,然后再在代码区查找;

        这里我只解释了父类指针访问子类重名函数的情况,没有解释虚析构函数不重名也能访问的情况。我想可能是析构函数有自己特殊的用法吧,可能每个类的析构函数都是同一个名字,而在代码中名字是不同的吧。这里如果有同学想明白了,希望能不吝赐教;

(3)通过子类对象初始化父类对象,通过父类对象不能访问子类重名函数(虚):

        按照上面的理论,子类对象初始化父类对象后,子类对象的数据成员会覆盖掉父类对象的数据成员,但是这里,父类原有的虚函数表是没有被覆盖掉的,父类对象的虚函数表指针还是自己的表指针;表指针里的虚函数地址还是父类自己的虚函数地址,所以此时通过父类对象只能访问到子类对象的数据成员(继承自父类的),访问自己代码区的成员函数和虚函数列表中的自己的虚函数,不能访问到子类虚函数列表中的虚函数;


正在回答

5 回答

是的,就是这样滴。


0 回复 有任何疑惑可以回复我~

在我们还没有学习多态的时候,父类和子类出现了同名函数,这个时候就称之为函数的隐藏(因为没有虚函数?)

如果我们没有在子类当中定义同名的虚函数,那么在子类虚函数表中就会写上父类的虚函数的函数入口地址;如果我们在子类当中也定义了虚函数,那么在子类的虚函数表中我们就会把原来的父类的虚函数的函数地址覆盖一下,覆盖成子类的虚函数的函数地址,这种情况就称之为函数的覆盖。

果然速度慢下来一字一字的把老师的话敲下来还是理解深刻一些。

0 回复 有任何疑惑可以回复我~

哇靠, 大佬啊, 感觉好细致

0 回复 有任何疑惑可以回复我~

我觉得不要想太多会应用就好:

VIRTUAL只需要加在父类里边(析构函数和同名成员函数)就好,析构函数前边加是为了防止没有释放子类对象的内存导致内存泄露,同名成员函数前加是为了父类实例化的对象指针能够指向子类数据成员。(这样基本包含了所有的点了)

1 回复 有任何疑惑可以回复我~

理解的挺好

0 回复 有任何疑惑可以回复我~

举报

0/150
提交
取消
C++远征之多态篇
  • 参与学习       66254    人
  • 解答问题       314    个

本教程将带领大家体会面向对象三大特性中的多态特性

进入课程

关于虚函数我自己的一点理论理解,不知道对不对?大家讨论一下,看我的理解有没有偏差

我要回答 关注问题
意见反馈 帮助中心 APP下载
官方微信