• 条款36:绝不重新定义继承而来的non-virtual函数


    1、为什么要绝不重新定义继承而来的non-virtual函数?

    考虑下述情况:

    //情况一
    class B{
    public:
        void mf();
        ...
    };
    class D:public B{...};
    
    D x;
    B *pB = &x;
    pB -> mf();//经由该指针调用	B::mf
    D *pD = &x;
    pD -> mf();//经由该指针调用B::mf
    
    //情况二
    class B{
    public:
        void mf();
        ...
    };
    
    class D: public B{
    public:
        void mf();     //遮掩了B:mf;
        ...
    }
    D x;
    B *pB = &x;
    pB -> mf();//调用B::mf
    D *pD = &x;
    pD -> mf();//调用D::mf        
    

    情况一是符合我们预想的,因为派生类没有重新定义non-virtual函数。
    但是情况二却是我们预想之外的,因为两个不同类型的指针指向的是同一个对象,但是发起函数调用时却调用了不同版本的函数。

    2、导致上述问题的原因?

    non-virtual函数都是静态绑定的,即:假如P是基类指针,无论P指向的基类对象还是派生类对象,它发起函数调用的版本都是基类的版本。

    与之对应的便是virtual函数,virtual函数是动态绑定的,假如P是基类指针,如果P指向的是基类对象,由P发起的函数调用则是基类版本的,如果P指向派生类,那么由P发起的函数调用则是派生类版本的。

    3、解释该条款的为什么要这么做?

    (1)pubilic继承与non-virtual函数

    首先public继承描述的是is-a关系
    其次,non-virtual函数强调不变性,忽略特异性。

    (2)基于上述两点:

    那么就应该:

    • D一定是B。
    • 适用于B的行为一定适用于D。

    假如重新定义了了B的函数mf(),基于编译器的上述规则,设计就出现了矛盾。

    • 如果要体现不变性:mf不应该被特化。
    • 如果要体现变化性:mf应该被设计为virtual。

    因此,绝不重新定义继承而来的non-virtual函数。

  • 相关阅读:
    adb稳定性monkey测试(转载)
    Cookie、sessionStorage、localStorage的异同
    Vue-eBookReader 学习笔记(初始化部分)
    ValueError: Max value is 14 解决方案
    Chrome 报错: Unchecked runtime.lastError: Could not establish connection. Receiving end does not exist.
    Bootstrap使用方法
    Vue笔记
    3D相册 复仇者联盟
    奔跑的少年
    钟表练习 html+css实现
  • 原文地址:https://www.cnblogs.com/lasnitch/p/12764188.html
Copyright © 2020-2023  润新知