15.6 为什么需要虚函数
在这个问题上,我们可能会问:“如果这个技术如此重要,并且使得任何时候都能调用‘正确’的函数,那么为什么它是可选的呢?为什么我甚至还需要知道它呢?”
问得好。回答关系到C++的基本哲学:“因为它不是相当高效的”。从前面的汇编语言输出可以看出,它并不是对于绝对地址的一个简单的CALL,而是为设置虚函数调用需要两条以上的复杂的汇编指令。这既需要代码空间,又需要执行时间。
一些面向对象的语言已经接受了这种途径,即晚捆绑对于面向对象程序设计是性质所固有的,所以应当总是出现,它不应当是可选的,而且用户并不一定需要知道它。这是在创造语言的设计时决定的,而这种特殊的方法对于许多语言是合适的。[1]而C++来自于C,在C中,效率是重要的。创造C完全是为了代替汇编语言以实现操作系统(从而改写操作系统—UNIX—使得比它的先驱更轻便)。发明C++的主要原因之一是让C程序员的工作具有更高效率。[2]当C程序员遇到C++时要问的第一个问题是“我将得到什么样的规模和速度效果”?如果回答是“除了函数调用时需要有一点额外的开销外,一切皆好”,那么许多人就会仍使用C,而不会改变到C++。另外,内联函数是不可能的,因为虚函数必须有地址放在VTABLE中。所以虚函数是可选的,而且该语言的默认是非虚拟的,这是最快的配置。Stroustrup声明他的方针是,“如果我们不用它,我们就不会为它花费额外的开销。”
因此,virtual关键字可以改变程序的效率。然而,当设计类时,我们不应当为效率问题担心。如果想使用多态,就在每处使用虚函数。当试图加速代码时,只需寻找可以不使用虚函数的函数(而且通常可能在其他方面获得更大收益—好的编程者会在查找瓶颈方面,而不是在猜测方面投入更多的工作)。
有些证据表明,C++中的规模和速度改进效果是在C的规模和速度的10%之内,并且常常更接近。能够得到更小的规模和更高速度的原因是C++可以有比用C更快的方法设计程序,而且设计的程序更小。
[1]例如,Smalltalk、Java及Python语言都成功地使用了这种方法。
[2]在C++的发源地—贝尔实验室中,汇集着大量的C程序员。尽力使这些C程序员的工作更加有效率,即使是改善一点点,也会为公司节省数百万美元的开销。