C++动态绑定与静态绑定

今天做题的时候遇到这样一个问题。

以下程序片段输出内容为:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class Demo {
public:
Demo():count(0) {}
~Demo() {}

void say(const std::string&msg) {
fprintf(stderr,"%s\n", msg.c_str());
}
private:
int count;
};

int main(int argc, char **argv) {
Demo* v = NULL;
v->say("hello world");
}

答案为 “hello, world”。

这个问题涉及到了 C++ 中动态绑定和静态绑定的知识。静态绑定又名前期绑定, early binding,是在编译期就确定的,通过对象调用。而动态绑定又名后期绑定, late binding,是在运行时确定的,通过地址实现。

只有采用“指针->函数()”“引用变量.函数()”的方式调用C++类中的虚函数才会执行动态绑定。对于C++中的非虚函数,因为其不具备动态绑定的特征,所以不管采用什么样的方式调用,都不会执行动态绑定。(本段及下面表格来自阿波123的博客,感谢。)





























        


代码形式



对于虚函数



对于非虚函数



作用



绑定方式



作用



绑定方式



类名::函数()



调用指定类的指定函数



静态绑定



调用指定类的指定函数



静态绑定



对象名.函数()



调用指定对象的指定函数



静态绑定



调用指定对象的指定函数



静态绑定



引用变量.函数()



调用引用对象所属类的指定函数



动态绑定



调用引用变量所属类的指定函数



静态绑定



指针->函数()



调用引用对象所属类的指定函数



动态绑定



调用指针变量所属类的指定函数



静态绑定


本题中, say()方法为非虚函数,故进行静态绑定,即使 v 是空指针,也可以根据 v 的类型调用该函数。

这令我想起了之前阅 《Effective C++ 》 时的一些收获,一起写在这里。

  1. 条款20: 宁以 pass-by-reference-to-const 替换 pass-by-value
    使用引用可以解决切割 (slicing) 问题。
  2. 条款36: 绝不重新定义继承而来的 non-virtual 函数
    因为如果重新定义,根据上述静态绑定和动态绑定的不同,会绑定到不同的函数中,从而效果不一样。
  3. 条款37: 绝不重新定义继承而来的缺少参数值
    由条款 36 重新定义 non-virtual 函数永远是错误的。对于 virtual 函数,其为动态绑定,而缺少参数值却是静态绑定!
❤采之欲遗谁,所思在远道。❤
0%