一张图讲明白重载、覆盖和隐藏的联系与区别!

学到类的继承这边会出现三个容易混淆的概念:重载(overload)、覆盖(override)和隐藏(hide)。

  • 重载:同一作用域内的几个函数名字相同但参数列表不同(见C++ Primer 6.4节)。
  • 覆盖:派生类对基类中有相同函数签名(指参数列表+返回类型)的函数进行重定义(来自GeeksforGeeks,见C++ Primer 15.2-3节)。
  • 隐藏:内作用域的函数会使外作用域的函数变得不可见。

如何厘清这三者之间的关系?给定两个函数,如何判断他们是重载/覆盖/隐藏?看下面这张图就够了。

一张图讲明白重载、覆盖和隐藏的联系与区别!_第1张图片

按照上图的判断过程,可以轻松判断main 函数中每一行代码的输出。

#include 

using std::cout;

struct Base
{
    void f() { cout << "Base f\n"; }
    void f(char) { cout << "Base f char\n"; }
    void f(int) { cout << "Base f int\n"; }
    virtual void g(char) { cout << "Base g char\n"; }
    virtual void g(int) { cout << "Base g int\n"; }
    virtual void h() { cout << "Base h\n"; }
};

struct Derived : public Base
{
    void f() { cout << "Derived f\n"; }
    void f(char) { cout << "Derived f char\n"; }
    void f(double) { cout << "Derived f double\n"; }
    virtual void g() { cout << "Derived g\n"; }
    virtual void g(char) { cout << "Derived g char\n"; }
    virtual void g(double) { cout << "Derived g double\n"; }
    virtual int h() { return 1; } // 如果参数列表相同,必须保证返回类型也相同,才能覆盖;如果返回类型不同,必须保证参数列表也不同,才能隐藏。
    //error: conflicting return type specified for 'virtual int Derived::h()'
    using Base::f;  // 使被基类被隐藏的f变得可见
};

int main()
{
    Derived d;
    Base *bp = &d;
    d.f();  // Derived f
    d.f(1);  // Base f int
    cout << "====\n";
    bp->f();  // Base f
    bp->f(1);  // Base f int
    cout << "====\n";
    d.g(1.1);  // Derived g double
    d.g('a');  // Derived g char
    d.g(1); // 二义性调用,参数是char还是double? error: virtual void Derived::g(char) or virtual void Derived::g(double)
    cout << "====\n";
    bp->g(); // 静态类型为基类基类没有名为g的函数不接受参数。error: candidate expects 1 argument, 0 provided
    bp->g('a');  // Derived g char
    bp->g(1);  // Base g int
    bp->g(1.1); //静态类型为基类,二义性调用,参数是char还是int? error: virtual void Base::g(char) or virtual void Base::g(int)
    cout << "====通过作用域运算符调用另一函数\n";
    d.Base::f();  // Base f
    bp->Base::g('a');  // Base g char
    return 0;
}

你可能感兴趣的:(C++,c++)