c++ 重载、覆盖、隐藏差异

这里写图片描述

1.成员函数重载(overload)的特征:

  (1)相同的范围(在同一个类中);

  (2)函数名字相同;

   (3)参数不同;

   (4)virtual关键字可有可无。

  (5)返回值可以不同

总之,函数重载与否看的是函数参数的个数、类型以及顺序

2.覆盖(override)(重写)是指派生类函数覆盖基类函数,特征是:

  (1)不同的范围(分别位于派生类与基类);

  (2)函数名字相同;

  (3)参数相同;

  (4)基类函数必须有virtual关键字。

  (5)返回值相同,否则报错;
  
  (6)覆盖函数的访问修饰符可以不同;(private到public及其他)

   重新定义一个基类中的重载函数将会隐藏所有该函数的其他基类版本。

  3.重定义(redefining)(也成为隐藏)是指派生类的函数屏蔽了与其同名的基类函数,规则如下:

     (1)不在同一作用域(分别位于派生类与基类)

     (2)函数名相同;

     (3)返回值可以不同;

     4)如果派生类的函数与基类的函数同名,但是参数不同。此时,不论有无virtual关键字,基类的函数将被隐藏(注意别与重载混淆)。

     5)如果派生类的函数与基类的函数同名,并且参数也相同,但是基类函数没有virtual关键字。此时,基类的函数被隐藏(注意别与覆盖混淆)。

    函数重载(overload)含义相对好理解,主要是重定义(redefining隐藏)与覆盖(override重写)容易混淆。

总结:

        覆盖(override重写)是针对基类虚函数(Virtual)而言的,在派生类中除了访问修饰符可以不同外,函数名、返回值和参数列表都要相同。

        重定义(redefining也称为隐藏),在派生类中除了函数名要相同外,其他(返回值、参数表、访问属性)都可不同。

另外有句话很重要:指针是什么类型,则指针调用的函数就是指针类型的函数(除了覆盖,这种情况)。

例如:Derive a; Base *p=&a;p->func();这里如果func()函数在基类中是虚函数,且在派生类中覆盖了这一函数,则p->func()调用的就是派生类的函数,否则调用的就是基类的func()函数,不论派生类是否重定义func()函数。

#include<iostream>
#include<string>
using namespace std;

class Base
{
private:
    virtual void display() 
    {
        cout<<"Base display()"<<endl;
    }
public:
    void say() 
    {
        cout<<"Base say()"<<endl;
    }
public:
    void exec() 
    {
        display();//覆盖;
        say();//重定义(Redefining隐藏);
    }
private:
    void fun1(string a) {cout<<"Base fun1(string)"<<endl;}
    void fun1(int a) {cout<<"Base fun1(int)"<<endl;}//overload,两个fun1函数在Base类的内部被重载

    };
    class ChildA:public Base
    {
    public:
        //override,基类中的display函数参数列表,函数名相同且有virtual修饰为虚函数,故此处为重写(覆盖);
        void display( )  
        {
            cout<<"ChildA display()"<<endl;
        }
        //redefining,fun1函数与基类的函数同名但参数列表不同,故为重定义;
        void fun1(int a,int b) {cout<<"ChildA fun1(int,int)"<<endl;}
        //redefining,say函数与基类函数同名,参数列表一样,但基类函数没有virtual修饰,故为重定义;
        void say()
        {
            cout<<"ChildA say()"<<endl;
        }
    };
    class ChildB:public Base
    {
    public:
        //redefining,与基类中fun1函数名、参数列表相同,但基类函数没有virtual修饰,故为重定义;
        //重定义函数的返回类型可以不同;
        int fun1(double a) 
        {
            cout<<"ChildB fun1(double)"<<endl;
            return 0;
        }
    };

    int main()
    {
        ChildA a;
        Base* b= &a;
        //display():version of DeriveA call(polymorphism)
        //say():version of Base called(allways )
        b->exec();  
        //b里边的函数display被A类重写(覆盖),say还是自己的;
        //什么指针就调用什么函数;
        b->say();

        a.exec(); //same result as last statement   
        a.say();
        ChildB c;
        c.fun1(1.1); //version of ChildB called

    }

猜你喜欢

转载自blog.csdn.net/u014253011/article/details/82661773