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 函数,其为动态绑定,而缺少参数值却是静态绑定!