重载、覆盖、隐藏的区别

重载

  • 重载是指同名函数具有不同的参数表。

  • 在同一访问区域内声明的几个具有不同参数列表(参数的类型、个数、顺序不同)的同名函数,程序会根据不同的参数列来确定具体调用哪个函数。

  • 对于重载函数的调用,编译期间确定,是静态的,它们的地址在编译期间就绑定了。

  • 重载不关心函数的返回值类型

  • 函数重载的特征

    • 相同的范围(同一个类中)
    • 函数名字相同
    • 参数不同
    • virtual关键字可有可无。
  • 实例

class A {
public:
    virtual double f(double);
    int f(double);   //声明出错:无法重载仅按返回值类型区分的函数:double f(double);
    double f(int);   //声明正确,参数类型不同
    double f(double, int);
    double f(int, double);
};

覆盖

  • 覆盖是指派生类中存在重新定义基类的函数,其函数名、参数列、返回值类型必须同父类中相应被覆盖的函数严格一致,覆盖函数和被覆盖函数只有函数体不同,当基类指针指向派生类对象,调用该同名函数时会自动调用子类中的覆盖版本,而不是父类中的被覆盖函数版本。

  • 函数调用在编译期间无法确定,因虚函数表存储在对象中,对象实例化时生成。因此,这样的函数地址是在运行期间绑定

  • 覆盖的特征

    • 不同的范围(分别位于派生类和基类)
    • 函数名字相同
    • 参数相同
    • 返回值类型相同
    • 基类函数必须有virtual关键字。

重载和覆盖的关系

  • 覆盖是子类和父类之间的关系,是垂直关系;重载是同一个类中方法之间的关系,是水平关系。

  • 覆盖只能由一对方法产生关系;重载是两个或多个方法之间的关系。

  • 覆盖要求参数列表相同;重载要求参数列表不同。

  • 覆盖关系中,调用方法是根据对象的类型来决定的,重载关系是根据调用时的实参表与形参表来选择方法体的。

隐藏

  • 隐藏是指派生类的函数屏蔽了与其同名的基类函数。

  • 如果派生类的函数与基类的函数同名,但参数不同,则无论有无virtual关键字,基类的函数都被隐藏。

  • 如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字,此时基类的函数被隐藏。

  • 隐藏的特征

    • 必须分别位于基类和派生类中
    • 必须同名
    • 参数不同的时候本身已经不构成覆盖关系了,所以此时有无virtual关键字不重要
    • 参数相同时就要看是否有virtual关键字,有就是覆盖关系,无就是隐藏关系

实例

#include<iostream>

using namespace std;

class Base {
public:
    virtual void f(float x) {
        cout << "Base::f(float)" << x << endl;
    }
    virtual void g(float x) {
        cout << "Base::g(float)" << x << endl;
    }
    void h(float x) {
        cout << "Base::h(float)" << x << endl;
    }
};

class Derived : public Base {
public:
    virtual void f(float x) {
        cout << "Derived::f(float)" << x << endl;
    }
    void g(int x) {
        cout << "Derived::g(int)" << x << endl;
    }
    void h(float x) {
        cout << "Derived::h(float)" << x << endl;
    }
};

class Derived2 :public Derived {
    void f(float x) {
        cout << "Derived2::f(float)" << x << endl;
    }
    void f(int x) {
        cout << "Derived2::f(int)" << x << endl;
    }
    void f(int x,double y) {
        cout << "Derived2::f(int,double)" << x << " " << y << endl;
    }
    void f(double x, double y) {
        cout << "Derived2::f(double,double)" << x << " " << y << endl;
    }
};

int main(int argc, char* argv[]) {
    Derived d;
    Base *pb = &d;  //基类指针指向派生类对象
    pb->f(3.14);    //f是覆盖关系
    pb->g(3.14);    //g是隐藏关系
    double val = 3.1415926;
    pb->g(val);
    pb->g(3);
    pb->h(3.14);    //h是隐藏关系
    Derived2 d2;
    Base *pb2 = &d2;  //基类指针指向派生类的派生类对象
    pb2->f(3.14);
    //重载
    Derived2 *pd = new Derived2();
    pd->f(1);
    pd->f(3.14,3.14);
    pd->f(3,3.14);
    pd->f(float(3.14));
    getchar();
    return 0;
}
  • 运行结果

这里写图片描述

©️2020 CSDN 皮肤主题: 技术工厂 设计师:CSDN官方博客 返回首页