我发现在子类函数中调用父类的方法, 即使没有发生名字覆盖或者虚函数改写, 感觉有点奇怪啊.. 还有继承自父类的属性, 也是这样...
我发现在子类函数中调用父类的方法, 即使没有发生名字覆盖或者虚函数改写, 感觉有点奇怪啊.. 还有继承自父类的属性, 也是这样...
假设 void printf() 这个函数基类子类中都有。现在我把基类中变为虚函数:
这是为什么?哪里有写着要调用子类函数了?为什么不是调用基类函数?
可选中1个或多个下面的关键词,搜索相关资料。也可直接点“搜索资料”搜索整个问题。
有虚函数时,每个对象的this指针都指向一个虚函数表(Virtual Table)的地址,这个表里存的就是虚函数的地址。编译的时候就决定了,普通函数调用时直接CALL这个函数的地址,而是虚函数时,是从这个虚表里取地址去调用的。
每个对象的this指针都指向一个虚函数表。。。。。。。每个对象?你是说基类子类的this指针都指向虚函数表?????
我设定的是基类函数为虚函数,按此说法,这是从虚表里调用的,那也应该调用的是基类的虚函数啊?
父类的这个函数是虚函数,子类里自然也是了,子类里这个关键字是可省略的
补充一下:
如果觉得我的回答难理解,可以就记住一个概念:普通函数是属于类的,虚函数是属于对象的。
也就是说,普通函数,指针类型是哪个类的,调用的函数就那个类的。
虚函数,不管指针类型是那个类的,你new的是谁,决定你最终调用的是谁的函数。
我就是想知道具体调用的流程是怎样的,你之前说从虚表里调用,这没问题。
那么基类里也有虚函数啊,他为什么调用子类的?
你说子类也自动变成虚函数。这也没问题,但同样是虚函数,为什么不调用基类却调用子类的?
还有,我就是想刨根问底,尽管来哈哈哈,越详细我越爽
因为规则就是这样设定的,编译器就得按这个规则来编译,这个没啥可说的。
编译的时候代码就生成成这样了。普通函数直接CALL这个函数的地址,要虚函数的话,得先取虚表地址 mov eax,[this] , 再取虚函数地址调用 call dword ptr [eax] 。就放了两句关键汇编,而且默认为虚函数地址正好在虚表中是第一个的时候就这样
想知道的更详细只有你自己去看汇编的,我已经没法表达了
原因:由于子类重载了基类的虚函数,所以在子类对象的虚函数表里面的函数地址是子类的,而不是父类的,所以p->printf(),肯定调用的是子类的printf函数了。
定义了虚函数之后,在执行的时候,系统会自动的匹配与之相对应的合适的成员函数。
这里的话p是指向son的指针,那么他会先调用son里面的成员函数。
p是指向son的指针,那么他会先调用son里面的成员函数。如果我没有设立虚函数呢?p是指向son的指针呀,它怎么不调用son函数?
如果子类实现了的就掉子类,子类没实现的就调父类的。