C++的动态绑定和静态绑定(二)

2014-11-24 12:03:59 · 作者: · 浏览: 1
译器的编译过程来进行解释。只看编译器是怎么编译带有标号的那些函数调用的行的。

行1. 在编译器眼中,p就是一个纯粹的A类指针,跟他指向的B类对象没有任何联系。因此,当看到
p->fA()时,编译器便去A的定义中寻找fA,找到了,于是生成调用代码。
行2. 这行如果不被注释,编译器去A的定义中寻找定义fB,但是找不到这个名字,便会输出错误信息。
行3. 编译器继续去A定义中寻找vfA,这次找到了,而且发现关键字virtual,于是,采用虚拟函数调用
代码生成技术,根据vfA的偏移值,生成代码调用虚拟函数表中该偏移值指向的函数。特别指出的
是,在静态编译期间,编译器只知道偏移值,并不知道运行时该偏移到底指向什么函数。实际效果
是,因为运行时,p指向的是B对象,因此调用的是B的虚拟函数vfA().
行4. 这行如果不被注释,编译器去A的定义中寻找名字vfB,找不到,出错。记住第一条原则,编译器
是静态编译,不知道p和类B有联系。
行5. 同4,找不到名字emptyA。
行6. 简单,找到名字emptyB.
行7. 简单,找到名字vfAonly。

行8. 从这里开始,函数由B类引用r调用。在编译器眼中,r就是一个纯粹的B类引用,他不假设r和A有任何
关系。因此这一行,编译器去B类定义寻找名字fA。由于B继承自A,包括所有A的public函数定义,
编译器成功找到A::fA。
行9. 类似行8,找到B自身的函数定义fB。
行10. 类似行3,编译器生成代码调用虚拟函数表某偏移指向的函数。运行时该偏移指向B::vfA.
行11. 编译器生成代码调用虚拟函数表某偏移指向的函数。运行时该偏移指向B::vfB.
行12. 简单,找到名字emptyA.
行13. 简单,找到名字A::emptyB. 因为B继承自A。
行14. 编译器生成代码调用虚拟函数表某偏移指向的函数。运行时该偏移指向B::vfAonly. 为什么编译器知道
指向的是B的虚拟函数vfAonly而不是A的非虚拟函数呢?这跟另一个静态编译规则,名字隐藏,有关。
继承类的作用域中如果有基类的同名函数,继承类中的名字将隐藏基类同名函数,因此这时,编译器看
不见A::vfAonly。


摘自 Slow Dance