1. 程式人生 > >同名覆蓋引發的問題(四十一)

同名覆蓋引發的問題(四十一)

C++ 同名覆蓋 賦值兼容 函數重寫

在子類繼承父類後,子類對象便可以當做父類對象使用了(兼容性)。包括:1、子類對象可以直接賦值給父類對象;2、子類對象可以直接初始化父類對象;3、父類對象可以直接指向子類對象;4、父類引用可以直接引用子類對象。那麽我們來編程看看子類對象的兼容性

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    int mi;
    
    void add(int v)
    {
        mi += v;
    }
    
    void add(int a, int b)
    {
        mi += (a + b);
    }
};

class Child : public Parent
{
public:
    int mv;
    
    void add(int a, int b, int c)
    {
        mv += (a + b + c);
    }
};

int main()
{
    Parent p;
    Child c;
    
    p = c;
    
    Parent p1(c);
    
    Parent& rp = c;
    Parent* pp = &c;
    
    rp.mi = 100;
    rp.add(5);
    rp.add(10, 10);
    
    //pp->mv = 1000;
    //pp->add(1, 10, 100);
    
    return 0;
}

我們先來看看第 38 行將子類對象 c 直接賦值給父類對象 p,這樣編譯會通過嗎?還有第 40 行的初始化操作。再將子類對象 c 賦值給父類對象的引用 rp,將父類對象的指針 pp 指向對象 c 的地址。通過 rp 調用父類對象的成員變量和成員函數,看看會報錯嗎?照理說這塊應該會發生同名覆蓋,我們看看編譯結果

技術分享圖片

編譯是通過的,也就證明沒有發生同名覆蓋。那麽我們再來將第 49 和 50 行的註釋去掉,看看通過指針 pp 指向的子類對象 c 直接調用子類對象的成員變量和成員函數會通過嗎?

技術分享圖片

我們看到編譯出錯了。下來我們來說下當使用父類指針(引用)指向子類對象時,子類對象便退化為父類對象,只能訪問父類中定義的成員,可以直接訪問被子類覆蓋的同名成員

。這也就不難解釋上面沒有發生同名覆蓋以及通過指針來調用子類對象的成員變量和成員函數出錯的情況了。

子類中可以重定義父類中已經存在的成員函數,這種重定義發生在繼承中,叫做函數重寫函數重寫是同名覆蓋的一種特殊情況。當函數重寫遇上賦值兼容會發生什麽呢?我們通過是來代碼來分析下

#include <iostream>
#include <string>

using namespace std;

class Parent
{
public:
    void print()
    {
        cout << "I'm Parent!" << endl;
    }
};

class Child : public Parent
{
public:
    void print()
    {
        cout << "I'm Child!" << endl;
    }
};

void how_to_print(Parent* p)
{
    p->print();
}

int main()
{
    Parent p;
    Child c;
    
    p.print();         // I'm Parent!
    c.print();         // I'm Child!
    
    cout << endl;
    
    how_to_print(&p);  // I'm Parent!
    how_to_print(&c);  // I'm Child!
    
    return 0;
}

我們分別在父類和子類中定義 print 函數,打印相關信息。我們期望的是 p.print() 打印的是 I'm Parent!;c.print() 打印的是 I'm Child!;在調用全局函數 how_to_print() 時,如果傳入的是父類指針,我們期望打印的是 I'm Parent!,如果傳入的是子類指針,則打印的是 I'm Child!。下來我們來編譯看看結果

技術分享圖片

我們直接調用的時候打印的是對的,但是在傳入對象的時候,打印的是錯的。我們傳入的是子類對象,但是打印出來的是父類的函數,我們會不會很奇怪呢?在編譯期間,編譯器只能根據指針的類型判斷所指向的對象,根據賦值兼容,編譯器認為父類指針指向的是父類對象。因此,編譯結果只可能是調用父類中定義的同名函數。那麽在編譯到 how_to_print(Parent* p) 這個函數時,編譯器不可能知道指針 p 究竟指向了什麽。但是編譯器沒有理由報錯。於是乎,編譯器認為最安全的做法是調用父類的 print 函數,因為父類和子類肯定都有相同的 print 函數。因此便出現了這個編譯結果,那麽編譯器的處理方法是合理的嗎?是期望的嗎?顯然從安全的角度來說,它的處理是合理的,但卻不是我們所期望的。在後面我們會繼續講解這個問題的。

通過對同名覆蓋的學習,總結如下:1、子類對象可以當做父類對象使用(賦值兼容);2、父類指針可以正確的指針子類對象;3、父類引用可以正確的代表子類對象;4、子類中可以重寫父類中的成員函數。


歡迎大家一起來學習 C++ 語言,可以加我QQ:243343083

同名覆蓋引發的問題(四十一)