zoukankan      html  css  js  c++  java
  • 条款37: 决不要重新定义继承而来的非虚函数

    class B {
    public:
      void mf();
      ...
    };
    
    class D: public B { ... };

    甚至对B,D或mf一无所知,也可以定义一个类型D的对象x,

    D x;                          // x是类型D的一个对象

    那么,如果发现这么做:

    B *pB = &x;                   // 得到x的指针

    pB->mf();                     // 通过指针调用mf

    和下面这么做的执行行为不一样:

    D *pD = &x;                   // 得到x的指针

    pD->mf();                     // 通过指针调用mf

    你一定就会感到很惊奇。

    如果mf是非虚函数而D又定义了自己的mf版本,行为就不会相同:

    class D: public B {
    public:
      void mf();                  // 隐藏了B::mf; 参见条款50
    
      ...
    
    };
    
    
    pB->mf();                     // 调用B::mf
    
    pD->mf();                     // 调用D::mf

    名字查找与继承:(函数调用步骤)

    假设调用p->mem()

    1.首先确定p的静态类型

    2.在p的静态类型对应的类中查找,如果找不到,则依次在直接基类中不断查找直至到达继承链的顶端,如果找遍了该类及其基类仍然找不到,编译器将报错

    3.一旦找到mem,就进行常规的类型检查,以确认对于当前找到的mem,本次调用是否合法

    4.假设调用合法,则编译器根据调用的是否是虚函数而产生不同的代码:

    如果mem是虚函数且我们是通过引用或指针进行的调用,则编译器产生的代码将在运行时确定到底运行该虚函数的哪个版本,依据是对象的动态类型;

    反之,则编译器将产生一个常规函数调用,即静态绑定

  • 相关阅读:
    数据结构的理解
    等价、偏序和全序
    等价、偏序和全序
    二叉树与树的理解
    SICP 习题 (2.10)解题总结: 区间除法中除于零的问题
    div:给div加滚动栏 div的滚动栏设置
    textarea文本域宽度和高度(width、height)自己主动适应变化处理
    OSX: 逻辑卷管理系统Core Storage(1)
    垂死挣扎还是涅槃重生 -- Delphi XE5 公布会归来感想
    string实现
  • 原文地址:https://www.cnblogs.com/ljygoodgoodstudydaydayup/p/3924468.html
Copyright © 2011-2022 走看看