class Instrument {
public:
virtual void play() {...}
}
class Violet : public Instrument {
public:
void play() {...}
}
void player(Instrument& i) {
i.play();
}
int main() {
Violet v;
tune(v);
}
有了多态,player 可以不必考虑 i 是哪个 instrument,直接调用 i.play() ,i 就会发出它应该发出的声音。但问题时怎么找到 play 的代码段呢?
如果基类方法不是 virtual, 运行时代码已经确定了,运行到 i.play(),就会自动跳到基类 play 代码段入口。(early binding)
但如果发现基类方法是 virtual,程序还不知道接下去到哪执行?这时会触发编译器进行 late binding 来生成对应的代码入口。
具体方法就是根据对象 v 中保存的 VPTR 指针找到 VTABLE 这张表,入口位于VTABLE[offset]。
VPTR 和 VTABLE 在对象 violet 实例化的时候已经生成好(violet 已经知道自己是个小提琴= =),直到基类 virtual 函数被调用时才触发索引过程。
因为虽然 violet 知道自己是个小提琴,但是 player 的代码段不能在编译时确定,如果舍弃多态,那么在编译时就可以绑定,即基类 play 函数代码。
现在需要在运行时根据传入的对象来确定 player 到底该生成什么样的代码,我到底是拉小提琴还是弹吉他。
late bingding 比 early binding 多了一个索引的过程,这个过程因为需要编译器的介入,减慢了调用的速度。
开发效率和程序效率不可兼得,barne 选择了前者,于是乎 c++ 有了 virtual 关键字。
(收起)