15.3 问题
运行程序Instrument2.cpp可以看到这个程序中的问题。调用输出的是Instrument:play。显然,这不是所希望的输出,因为我们知道这个对象实际上是Wind而不是一个Instrument。应当调用的是Wind:play。为此,由Instrument派生的任何对象不论它处于什么位置都应当使用它的play()版本。
然而,当对函数用C方法时,Instrument2.cpp的行为并不使人惊奇。为了理解这个问题,需要知道捆绑(binding)的概念。
15.3.1 函数调用捆绑
把函数体与函数调用相联系称为捆绑(binding)。当捆绑在程序运行之前(由编译器和连接器)完成时,这称为早捆绑(early binding)。我们可能没有听过这个术语,因为在过程型语言中不会有这样的选择:C编译只有一种函数调用方式,就是早捆绑。
上面程序中的问题是早捆绑引起的,因为编译器在只有Instrument地址时它并不知道要调用的正确函数。
解决方法被称为晚捆绑(late binding),这意味着捆绑根据对象的类型,发生在运行时。晚捆绑又称为动态捆绑(dynamic binding)或运行时捆绑(runtime binding)。当一个语言实现晚捆绑时,必须有某种机制来确定运行时对象的类型并调用合适的成员函数。对于一种编译语言,编译器并不知道实际的对象类型,但它插入能找到和调用正确函数体的代码。晚捆绑机制因语言而异,但可以想象,某些种类的类型信息必须装在对象自身中。稍后将会看到它是如何工作的。