1. 程式人生 > >C++知識積累:過載、隱藏和重寫的區別

C++知識積累:過載、隱藏和重寫的區別

基本概念:
過載:是指同一可訪問區內被宣告的幾個具有不同引數列(引數的型別,個數,順序不同)的同名函式,根據引數列表確定呼叫哪個函式,過載不關心函式返回型別。

示例:

class A{
public:
  void test(int a);
  void test(double a);//過載
  void test(int a, double b);//過載
  void test(double a, int b);//過載
  int test(int a);         //錯誤,過載的返回型別必須相同
};

那麼這裡什麼叫做不關心函式返回型別呢?如下所示:

#include <iostream>
using namespace std;

class A
{
public:
    A(){};
    ~A(){};
    int test(int a,int b) {return a+b; }
    char test(int a) {return '5'+a; }
};
int main()
{
    A *a=new A();
    cout << a->test(1) << endl;
    return 0;
}

這裡呼叫一個引數的char test(int a)是完全可以的,但是如果過載函式為char test(int a,int b)的話,由於其引數列表與int test(int a,int b)相同,那麼就會提示char test(int a,int b)不能被過載,可想而知,在我們呼叫test這個函式的時候,如果以test(a,b)去呼叫,那系統又怎麼知道該呼叫int test(int a,int b)還是char test(int a,int b)呢?
由此我們也能看出,過載並非不能改變返回值型別,相反,只要合法,你可以隨意改變返回值型別,不過不管你是否改變返回值型別,你的過載函式的引數列表是必須改變的,換句話說,過載函式即是在函式名相同的情況下改變引數列表,函式返回型別是否更改並無影響,這也就是為什麼過載不關心函式返回型別了。

隱藏:是指派生類的函式遮蔽了與其同名的基類函式,注意只要同名函式,不管引數列表是否相同,基類函式都會被隱藏。

示例:

#include <iostream>
using namespace std;

class Base
{
public:
    void test(int a,int b){ cout << "Base called!" << endl; }
};

class Derive : public Base
{
public:
    void test(int a){ cout << "Derive  called!" << endl; }
};

int main()
{
    Derive d;
    d.test(1);//   "Derive  called!" 呼叫子類的fun函式
    d.test(1, 1);//   錯誤,此時fun函式只能接收1個引數
    return 0;
}

也就是說,只要在子類中存在父類中的同名函式,那麼通過子類物件是無法呼叫父類相應的同名函式,只能呼叫當前子類的同名函式。

重寫(覆蓋):是指派生類中存在重新定義的函式。其函式名,引數列表,返回值型別,所有都必須同基類中被重寫的函式一致。只有函式體不同(花括號內),派生類呼叫時會呼叫派生類的重寫函式,不會呼叫被重寫函式。重寫的基類中被重寫的函式必須有virtual修飾。

示例:

#include<iostream>

using namespace std;

class Base
{
public:
    virtual void test(int a){ cout << "Base called !" << i << endl;}
};

class Derived : public Base
{
public:
    virtual void test(int a){ cout << "Derived  called! " << i << endl;}
};
int main()
{
    Base b;
    Base * pb = new Derived();
    pb->test(3); //   Derived  called!
    return 0;
}

總結一下:

過載、隱藏和重寫的區別:

(1)過載是對於同一類而言的,即過載函式與被過載的函式必須在同一類中;隱藏函式與被隱藏函式存在於不同類中;重寫與被重寫的函式是存在於父類與繼承類中,也就是在不同的類中。
(2)過載必須改變引數列表;隱藏既可以改變引數列表也可以不改變,如果隱藏函式不改變引數列表則相當於重寫;而重寫則不能改變引數列表,如果改變就相當於隱藏函數了。
(3)重寫函式的基類同名函式必須有virtual修飾,隱藏函式和被隱藏函式、過載函式和被過載函式都可以有virtual修飾,也可以沒有。
(4)如果子類中存在隱藏函式,那麼父類中被隱藏函式的所有過載函式都無法在子類中呼叫,但是仍然可以呼叫子類中的重寫函式。
如下所示:

#include <iostream>

using namespace std;

class A
{
public:
    A(){};
    ~A(){};

    virtual int test(int a,int b)
    {
        cout<<"A::int test(int a,int b) called!"<<endl;
        return 0;
    }
    virtual char test(int a)
    {
        cout<<"A::char test(int a) called!"<<endl;
        return '0';
    }
};
class B:public A
{
public:
    B(){};
    ~B(){};

    int test(int a,int b,int c)     //隱藏
    {
        cout<<"B::int test(int a,int b,int c) called!"<<endl;
        return 0;
    }
    char test(int a)   //重寫
    {
        cout<<"B::char test(int a) called!"<<endl;
        return '0';
    }
};

int main()
{
    B b;
    b.test(3,2,1);    //"B::int test(int a,int b,int c) called!"  呼叫B中的test隱藏函式
    b.test(1);    //"B::char test(int a) called!"   呼叫B中的test重寫函式
    return 0;
}