C++ 动态绑定与静态绑定
今天做题的时候遇到这样一个问题。
以下程序片段输出内容为:
| 1 | class Demo { | 
这个问题涉及到了 C++ 中动态绑定和静态绑定的知识。静态绑定又名前期绑定, early binding,是在编译期就确定的,通过对象调用。而动态绑定又名后期绑定, late binding,是在运行时确定的,通过地址实现。
只有采用 “指针 -> 函数 ()” 或 “引用变量。函数 ()” 的方式调用 * C++ 类中的虚函数才会执行动态绑定。对于 C++* 中的非虚函数,因为其不具备动态绑定的特征,所以不管采用什么样的方式调用,都不会执行动态绑定。(本段及下面表格来自阿波 123 的博客,感谢。)
| 代码形式 | 对于虚函数 | 对于非虚函数 | ||
| 作用 | 绑定方式 | 作用 | 绑定方式 | |
| 类名:: 函数 () | 调用指定类的指定函数 | 静态绑定 | 调用指定类的指定函数 | 静态绑定 | 
| 对象名. 函数 () | 调用指定对象的指定函数 | 静态绑定 | 调用指定对象的指定函数 | 静态绑定 | 
| 引用变量. 函数 () | 调用被引用对象所属类的指定函数 | 动态绑定 | 调用引用变量所属类的指定函数 | 静态绑定 | 
| 指针 -> 函数 () | 调用被引用对象所属类的指定函数 | 动态绑定 | 调用指针变量所属类的指定函数 | 静态绑定 | 
本题中, say() 方法为非虚函数,故进行静态绑定,即使 v 是空指针,也可以根据 v 的类型调用该函数。
这令我想起了之前阅 《Effective C++ 》 时的一些收获,一起写在这里。
- 条款 20: 宁以 pass-by-reference-to-const 替换 pass-by-value
 使用引用可以解决切割 (slicing) 问题。
- 条款 36: 绝不重新定义继承而来的 non-virtual 函数
 因为如果重新定义,根据上述静态绑定和动态绑定的不同,会绑定到不同的函数中,从而效果不一样。
- 条款 37: 绝不重新定义继承而来的缺少参数值
 由条款 36 重新定义 non-virtual 函数永远是错误的。对于 virtual 函数,其为动态绑定,而缺少参数值却是静态绑定!