Effective C++条款36:继承与面向对象之(绝不重新定义继承而来的non-virtual函数)

一、看一个隐藏non-virtual函数的例子

  • 假设class D以public的方式继承于class B,代码如下:
class B {
public:
    void mf();
};
class D :public B {};

int main()
{
    D x;

    B *pB = &x;
    pB->mf();   //调用B::mf()

    D *pD = &x;
    pD->mf();   //调用D::mf()

    return 0;
}

二、静态绑定与动态绑定

静态绑定

  • 当我们调用non-virtual函数时,调用的函数版本与指针的类型有关
  • 例如,上面的pB指针在初始化时,将与D对象中的B对象所绑定;上面的pD指针在初始化时,将与D对象所绑定。这是静态绑定
  • 因此,pB调用的是B::mf();pD调用的是D::mf()

动态绑定

  • 当我们调用virtual函数时,调用的函数版本与指针所指的对象有关
  • 对virtual函数的调用,是在代码运行期间执行的。例如,如果上面的D::mf()是一个虚函数,那么会有:
class B {
public:
    virtual void mf();
};
class D :public B {
public:
    virtual void mf();
};

int main()
{
    D x;

    B *pB = &x;
    pB->mf();   //调用D::mf()

    D *pD = &x;
    pD->mf();   //调用D::mf()

    return 0;
}

三、为什么不建议派生类隐藏基类的non-virtual函数

  • 在条款32介绍过,public继承意味着is-a关系,条款34描述了为什么在class内声明一个non-virtual函数会为该class建立起一个不变性,凌驾其特异性。如果:
    • 我们在派生类中隐藏了基类的non-virtual函数,那么基类与派生类就会产生行为上的不一致,is-a关系就消失了
    • 如果想要表现出派生类与基类的不同,那么应该将函数声明为virtual(其中虚析构函数是一个例子)

四、总结

  • 绝对不要重新定义继承而来的non-virtual函数
发布了1525 篇原创文章 · 获赞 1085 · 访问量 45万+

猜你喜欢

转载自blog.csdn.net/qq_41453285/article/details/104817474