我理解的虚函数
曾经在微博看到大牛说道,面试c++能力,虚函数能摆谈一个小时就是不错的。
先列出问题。
1. c++中的关键词角度
Virtual 函数,纯虚函数,虚继承 。
2. 面向c++对象模型角度 看待虚函数
3. 虚函数的使用角度
结合ctor ,dtor等等
4. 高级主题,简要说明虚函数的优点、缺点
5.高级主题,请举例说明虚函数性能低的情形,并给出解决方案。
这里,我的回答是:
1. c++中的关键词角度
Virtual 函数(多态的基础),纯虚函数(对应 类为抽象类),虚继承 (使用于多重继承 对应父类为虚基类)。
2. 面向c++对象模型角度 看待虚函数
首先要懂虚表,(基础是分开一般函数(没有使用virtual关键词修饰的)的布局,还有知道dtor位于虚表)
在不同的继承层次(线性,扇形,钻石型)知道,虚表的布局。
还有使用了多态的函数如何转换成 c语言 (我理解:先找到虚表,然后找到对应函数指针)
3. 虚函数的使用角度
ctor为什么不能够调用虚函数(我理解:所有的子类成员还没有初始化, 此时访问时机不对。)
dtor为什么要设置为虚函数(调用子类dtor一次,就逐层销毁了所有(父类的,子类的)资源 )
4. 高级主题,简要说明虚函数的优点、缺点(答案详细参考引用文档1,2)
优点:我理解,就是多态
缺点:这里多说点
a.
比起编译时就确定地址的同类功能的函数调用, 动态连编时有效率损失.
b.
从指令级别讲,
(1.虚函数的不确定性,会让编译器的 指令预测(或者说流水线技术)失效(详细参考)
(2. 多了几条汇编指令(运行时得到对应类的函数的地址)
(3. 编译器不能内联优化(仅在用父类引用或者指针调用时,不能内联)
5. 高级主题,请举例说明虚函数性能低的情形,并给出解决方案。(答案详细参考引用文档1,3)
当虚函数位于多层循环嵌套的核心部分时,这种情况更严重。还有另外一种性能下降显著的情况:当一系列虚函数频繁被调用时,我们不得不支付程序多次穿过“虚边界”的消耗。
解决方法很简单:把抽象提高到更高层即可。总的思路是不要让程序频繁在“虚-虚”或者“虚-非虚”之间切换。抽象提高后,把一系列虚函数或者循环中的虚函数都转移到更高一层,大大减低了切换的次数。
更多的关于虚函数的效率
详细点,效率有损失,数量级到底有多少,曾经有网友测试,1亿次系统调用会损失约1s,我个人觉得有点微不足道哈。但是这个测试案例不一定有代表性。
a.
虚函数调用效率和继承层数无关;
b.
其实虚函数还是挺快的。虚函数的效率到底低不低和实际要调用的函数的耗时有关,当函数本身的的耗时越长,则虚函数的影响则越小。
c.
如果真的要完全移除虚函数,那么如果要实现运行时多态,则要用到函数指针,据上面的分析,函数指针基本具有虚函数的所有缼点(要传递函数指针,同样无法内联,同样影响流水线),且函数指针会使代码混乱。
补充:
幻の上帝 网友 提出使用 CRTP模式 解决效率问题。
shanehan 网友提出 使用 boost::bind boost::function来替代虚函数。
参考文档:
1. c++ 虚函数机制效率问题(关于流水线)
< http://blog.csdn.net/metalkittie/article/details/3281916>
2. C++中虚函数(virtual function)到底有多慢
< http://blog.csdn.net/hengyunabc/article/details/7461919>
3. 【C++】虚函数的性能和vtable的细节——《C++游戏编程》读书笔记1
< http://hi.baidu.com/springlie/bl ... 2a7f15b21bba55.html>
4.[C++虚函数系列1]如何使用CRTP模式解决虚函数的效率损失问题? (
http://blog.chinaunix.net/uid-9605822-id-2000053.html
曾经在微博看到大牛说道,面试c++能力,虚函数能摆谈一个小时就是不错的。
先列出问题。
1. c++中的关键词角度
Virtual 函数,纯虚函数,虚继承 。
2. 面向c++对象模型角度 看待虚函数
3. 虚函数的使用角度
结合ctor ,dtor等等
4. 高级主题,简要说明虚函数的优点、缺点
5.高级主题,请举例说明虚函数性能低的情形,并给出解决方案。
这里,我的回答是:
1. c++中的关键词角度
Virtual 函数(多态的基础),纯虚函数(对应 类为抽象类),虚继承 (使用于多重继承 对应父类为虚基类)。
2. 面向c++对象模型角度 看待虚函数
首先要懂虚表,(基础是分开一般函数(没有使用virtual关键词修饰的)的布局,还有知道dtor位于虚表)
在不同的继承层次(线性,扇形,钻石型)知道,虚表的布局。
还有使用了多态的函数如何转换成 c语言 (我理解:先找到虚表,然后找到对应函数指针)
3. 虚函数的使用角度
ctor为什么不能够调用虚函数(我理解:所有的子类成员还没有初始化, 此时访问时机不对。)
dtor为什么要设置为虚函数(调用子类dtor一次,就逐层销毁了所有(父类的,子类的)资源 )
4. 高级主题,简要说明虚函数的优点、缺点(答案详细参考引用文档1,2)
优点:我理解,就是多态
缺点:这里多说点
a.
比起编译时就确定地址的同类功能的函数调用, 动态连编时有效率损失.
b.
从指令级别讲,
(1.虚函数的不确定性,会让编译器的 指令预测(或者说流水线技术)失效(详细参考)
(2. 多了几条汇编指令(运行时得到对应类的函数的地址)
(3. 编译器不能内联优化(仅在用父类引用或者指针调用时,不能内联)
5. 高级主题,请举例说明虚函数性能低的情形,并给出解决方案。(答案详细参考引用文档1,3)
当虚函数位于多层循环嵌套的核心部分时,这种情况更严重。还有另外一种性能下降显著的情况:当一系列虚函数频繁被调用时,我们不得不支付程序多次穿过“虚边界”的消耗。
解决方法很简单:把抽象提高到更高层即可。总的思路是不要让程序频繁在“虚-虚”或者“虚-非虚”之间切换。抽象提高后,把一系列虚函数或者循环中的虚函数都转移到更高一层,大大减低了切换的次数。
更多的关于虚函数的效率
详细点,效率有损失,数量级到底有多少,曾经有网友测试,1亿次系统调用会损失约1s,我个人觉得有点微不足道哈。但是这个测试案例不一定有代表性。
a.
虚函数调用效率和继承层数无关;
b.
其实虚函数还是挺快的。虚函数的效率到底低不低和实际要调用的函数的耗时有关,当函数本身的的耗时越长,则虚函数的影响则越小。
c.
如果真的要完全移除虚函数,那么如果要实现运行时多态,则要用到函数指针,据上面的分析,函数指针基本具有虚函数的所有缼点(要传递函数指针,同样无法内联,同样影响流水线),且函数指针会使代码混乱。
补充:
幻の上帝 网友 提出使用 CRTP模式 解决效率问题。
shanehan 网友提出 使用 boost::bind boost::function来替代虚函数。
参考文档:
1. c++ 虚函数机制效率问题(关于流水线)
< http://blog.csdn.net/metalkittie/article/details/3281916>
2. C++中虚函数(virtual function)到底有多慢
< http://blog.csdn.net/hengyunabc/article/details/7461919>
3. 【C++】虚函数的性能和vtable的细节——《C++游戏编程》读书笔记1
< http://hi.baidu.com/springlie/bl ... 2a7f15b21bba55.html>
4.[C++虚函数系列1]如何使用CRTP模式解决虚函数的效率损失问题? (
http://blog.chinaunix.net/uid-9605822-id-2000053.html