1. 程式人生 > >多態實現--虛函數與純虛函數

多態實現--虛函數與純虛函數

裏的 對象 ios 動物類 編譯 out 問題 為我 virtual

多態實現--虛函數與純虛函數

  • C++中實現多態是使用虛函數表的方法實現的。
  • 那麽具體怎麽實現的呢?

舉例說明

  • 假設有這樣一個多態場景:
  • 有一個基類動物(animal類),動物裏面又有兩個派生類:貓(cat類)和狗(dog類)。現在要求動物類有一個共同的方法:叫聲(voice成員函數),但貓和狗叫聲是不同的(即:它們的叫聲實現方法不同)。
  • 那麽代碼怎麽寫呢?

多態的代碼實現

#include <iostream>
using namespace std;

//1、 定義一個純虛函數
class animal
{
public:
    virtual void voice()= 0;    //純虛函數voice
};

//2、 定義貓(cat)狗(dog)類,共同繼承自animal,但對voice進行了具體實現
class cat:public animal
{
public:
    virtual void voice()
    {
        cout <<"喵喵喵"<<endl;
    }
};

class dog:public animal
{
public:
    virtual void voice()
    {
        cout <<"汪汪汪"<<endl;
    }
};

//3、那麽下一步就要給貓和狗做一個統一接口了,傳參用基類指針。這個接口只有一個功能,就是調用動物叫聲voice。
void animal_voice(animal * a)
{
    a->voice();
}

//4、 多態寫好了,我們來調用一下試試,寫個test看看這個多態有沒有問題。我們分別定義一個貓狗對象,來調用統一接口,看看它們的叫聲是否相同。

void test()
{
    cat c;
    dog d;
    animal_voice(&c);
    animal_voice(&d);
}

int main()
{
    test();
    return 0;
}
  • 驗證結果:

    喵喵喵
    汪汪汪

說明這個多態已實現完成。

多態原理

  • 那麽多態的原理是怎麽樣的呢?為什麽這樣寫代碼,就能實現貓和狗叫聲不同,它們明明調用的是同一個接口呀?

  • 我們知道C++在編譯時為我們做了很多背後的工作。它為cat和dog分別生成了一張虛函數表,將函數地址(也就是函數指針)記錄在各自的虛函數表中。如圖所示。

    • cat的虛函數表:
cat的虛函數表
cat的voice函數的地址
- dog的虛函數表:
dog的虛函數表
dog的voice函數的地址
  • 這樣當我們用接口調用cat和dog的voice函數時,它們會各自在自己的虛函數表裏找到自己的voice函數地址,然後根據這個地址來進行調用了。怎麽樣,多態實現很簡單吧?

虛函數與純虛函數

  • 那麽animal裏的純虛函數virtual void voice()= 0;只能這樣寫嗎?它可以像下面這樣寫成虛函數嗎?
    ```
    virtual void voice()
    {

}
```

  • 答案是可以,但它們是不同的。這裏的虛函數是有實現的,只是它的實現方法是空,那麽在cat和dog中我們再次實現這個voice就相當於重寫(也就是說,我們也可以選擇省略(即:不重寫)這個voice)。但如果寫成純虛函數,那麽我們就必須要在cat和dog中具體實現voice。

  • 也就是這裏的虛函數是有這個函數的實現,只是為空;而純虛函數是這個函數根本還沒實現。

多態實現--虛函數與純虛函數