在了解静态绑定和动态绑定之前,先了解什么是对象的静态类型,什么是对象的动态类型。


  • 对象的静态类型:对象在声明时采用的类型。是在编译器决定的。
  • 对象的动态类型:目前所指对象的类型。是在运行期决定的。
动态类型可以更改,而静态类型不可更改。看一个示例
  1. class Base
  2. {
  3. public:
  4. void setData(int i=10)
  5. {
  6. cout <<" virtual int Base::setData()"<<endl;
  7. }
  8. virtual int getData()
  9. {
  10. cout <<" virtual int Base::getData()"<<endl;
  11. }
  12. private:
  13. int m_value;
  14. };
  15. class Derive: public Base
  16. {
  17. public:
  18. void setData(int i=20)
  19. {
  20. cout <<" virtual int Derive::setData()"<<endl;
  21. }
  22. virtual int getData()
  23. {
  24. cout <<" virtual int Derive::getData()"<<endl;
  25. }
  26. };
  27. int _tmain(int argc, _TCHAR* argv[])
  28. {
  29. Derive *pd = new Derive;//pd的静态类型为Derive,动态类型也为Derive
  30. Base *pb = pd; //pb的静态类型为Base,动态类型为Derive
  31. return 0;
  32. }
搞清楚了什么是对象的静态类型,什么是对象的动态类型。
下面来介绍下什么是静态绑定,什么是动态绑定。

  • 静态绑定:绑定的对象是静态类型。某特性依赖于对象的静态类型,发生在编译期。
  • 动态绑定:绑定的对象是动态类型。有特性依赖于对象的动态类型,发生在运行期。
只有虚函数才使用的是动态绑定,其他的全部是静态绑定。

我们用pb,pd分别调用非虚函数,
  1. Derive *pd = new Derive;
  2. Base *pb = pd;
  3. pb->setData();
  4. pd->setData();
输出:

因为setData是静态绑定的,也就是编译器会在编译期根据对象的静态类型来选择函数。    pb的静态类型是Base,pd的静态类型是Derive。

我们用pd,pb分别调用虚函数

因为getData是虚函数,所以是动态绑定的。动态类型都是Derive*。
分别调用了基类的函数和派生类的函数。注:这样的设计特别不好,派生类与基类之间发生了名称遮掩。只是为了静态绑定和动态绑定才这么写的。如果派生类和基类是is-a关系,任何情况下都不要继承一个non-virtual函数。

注:指针和引用的动态类型与静态类型可能会不一致,但是对象的静态类型与动态类型是一致的。Derive d. d.setData()  d.getData()调用的都是派生类的成员函数。

当虚函数有缺省参数的时候,情况变得有点复杂。因为缺省参数采用的是静态绑定。
  1. class Base
  2. {
  3. public:
  4. virtual void getData(int i=10)
  5. {
  6. cout <<" virtual int Base::getData()" << i <<endl;
  7. }
  8. };
  9. class Derive: public Base
  10. {
  11. public:
  12. virtual void getData(int i = 20)
  13. {
  14. cout <<" virtual int Derive::getData()" << i <<endl;
  15. }
  16. };
  17. int _tmain(int argc, _TCHAR* argv[])
  18. {
  19. Derive *pd = new Derive;
  20. Base *pb = pd;
  21. pb->getData();
  22. pd->getData();
  23. return 0;
  24. }
输出:

虽然调用的都是缺省参数,由于缺省参数采用的是静态绑定。因此才会得到这样的结果。为了防止这样的情况出现:effective c++专门指出了一条:绝不重新定义继承而来的缺省参数。为了避免这样的结果,有一种方法就是使用NVI(non-virtual interface) :在基类中声明一个共有的非虚函数并给出缺省参数(因为是静态绑定),在其中调用私有的虚函数,这样在调用派生类方法时。由于共有非虚函数采取的是静态绑定,且派生类肯定继承了非虚函数。因此调用该函数时,默认的参数即可一直。

C++ 静态绑定与动态绑定------绝不重新定义继承而来的缺省参数的更多相关文章

  1. 《effective C++》:条款37——绝不重新定义继承而来的缺省参数值

    引子: 阿里的一道题: #include <IOSTREAM> using namespace std; class A{ public: ) { cout<<"a~ ...

  2. [EffectiveC++]item37:绝不重新定义继承而来的缺省参数值

    绝不重新定义继承而来的缺省参数值 静态类型 动态类型

  3. c++ 切勿重新定义继承来的带缺省参数的函数

    切勿重新定义继承来的带缺省参数的函数.我们知道,继承来的函数是virtual 的,至于原因在上一节中已经说明了,即“切勿重新定义父类non-virtual函数”.所以确切的描述应该是“切勿重新定义继承 ...

  4. 条款37:绝不重新定义继承而来的缺省参数值(Never redefine a function's inherited default parameter value)

    NOTE: 1.绝不重新定义一个继承而来的缺省参数值,因为缺省参数值都是静态绑定的,而virtual 函数-----你唯一应该覆盖的东西----却是动态绑定的.

  5. Effective C++ -----条款37:绝不重新定义继承而来的缺省参数值

    绝对不要重新定义一个继承而来的缺省参数值,因为缺省参数值都是静态绑定,而virtual函数-----你唯一应该覆写的东西-----却是动态绑定.

  6. 读书笔记_Effective_C++_条款三十七:绝不重新定义继承而来的缺省参数值

    先看下面的例子: enum MyColor { RED, GREEN, BLUE, }; class Shape { public: ; }; class Rectangle: public Shap ...

  7. 【36】绝不重新定义继承而来的non-virtual方法

    1.绝不重新定义继承而来的non-virtual方法,为什么? 首先想想,non-virtual方法是干什么的?也就是说,它的使用场景.父类的non-virtual方法,其实就是告诉子类,继承实现,子 ...

  8. Effective C++ -----条款36:绝不重新定义继承而来的non-virtual函数

    绝对不要重新定义继承而来的non-virtual函数.

  9. 条款36:绝不重新定义继承而来的non-virtual函数(Never redefine an inherited non-virtual function)

    NOTE: 1.绝对不要重新定义继承而来的non-virtual函数.

随机推荐

  1. 第四周课堂笔记4th

    编码     Ascii美国 一个字节表示一个字符,必能表示汉子 大写字母65-90  小写字母97-122 265个位置 8位表示一个字节,  8bit=1byte GBK  中国 只包含本国文字 ...

  2. 普及组R4

    T3 链接:C 输入一个长度为n的数组a[i],下标从0开始(0到n-1) 保证n是2的整数次幂, 对于每个i (0 <= i < n) 求所有满足((i & j) == j)的a ...

  3. POJ 1269 /// 判断两条直线的位置关系

    题目大意: t个测试用例 每次给出一对直线的两点 判断直线的相对关系 平行输出NODE 重合输出LINE 相交输出POINT和交点坐标 1.直线平行 两向量叉积为0 2.求两直线ab与cd交点 设直线 ...

  4. Cefsharp实现快捷键功能

    原文:Cefsharp实现快捷键功能 1 . 实现IKeyboardHandler接口 public class KeyBoardHander : IKeyboardHandler { public ...

  5. 半宿了,仿写了个CList模板类,留着以后用吧

    难题还是很多阿.模板类.本身就是个问题 要考虑到各个方面,哎.问题很多 比如,如果模板类型为数值型.指针型数据,倒也可以 但是如果模板类型为聚合型,就麻烦了,判断.比较,什么乱七八糟的,都麻烦了. 哎 ...

  6. HttpClientUitl工具类

    public class HttpClient { private CloseableHttpClient httpClient; public HttpClient() { this.httpCli ...

  7. 通过ID获取元素 注:获取的元素是一个对象,如想对元素进行操作,我们要通过它的属性或方法。

    通过ID获取元素 学过HTML/CSS样式,都知道,网页由标签将信息组织起来,而标签的id属性值是唯一的,就像是每人有一个身份证号一样,只要通过身份证号就可以找到相对应的人.那么在网页中,我们通过id ...

  8. No converter found for return value of type: class com.alibaba.fastjson.JSON解决办法

    默认情况下,springMVC的@ResponseBody返回的是String类型,如果返回其他类型则会报错.使用fastjson的情况下,在springmvc.xml配置里加入: <mvc:a ...

  9. xcart-子分类/语言不显示

    由于数据库的版本不同,表名会区分大小写的情况,这样就导致xcart语言相关的信息显示不出来,此时只需更改根目录下的init.php文件,如下: 改成小写的就OK了.

  10. P3718 [AHOI2017初中组]alter

    贪心+二分答案 二分最终答案长度 主要问题在check上 ~~我代码写得巨丑,大家还是不要看我的代码了~~ ------------ 1:当mid大于1的时候,贪心策略是这样的: 当前连续的长度大于m ...