C++面向對象-22-多態基本語法

前面內容學習了繼承,在面向對象三大核心概念,我們學習完了封裝,繼承,剩下一個多態。這篇開始學習多態的基本概念和C++中多態基本使用。

1. 多態分兩類

靜態多態:函數重載和運行符重載屬於靜態多態,服用函數名
動態多態:派生類和虛函數實現運行時多態

這塊的知識點和Java中思想是一樣的。例如Java中經常遇到的面試題,你能說一下Java中的多態嗎。一般來說標準答案是這樣的:

      多態是面向對象三大核心,多態就是有多種形態,分兩種情況。1)在單個類中,多態的表現爲函數的重載,就是共用一個函數名,參數個數,參數類型不同,這些同名函數完成不同的功能,這就是單個類中的多態表現。 2)在繼承中,子類繼承父類,子類可以修改父類中已有的函數的行爲,這個動作叫做重寫。就是子類重寫父類的方法,這也是多態。然後適當舉例,工作中用到多態的例子,這樣回答,面試官基本都滿意,很清楚表達你對面向對象三大特點的掌握。

      在C++中,多態也是這兩點。也分成靜態多態和動態多態。結合上面Java中知識,理解上面靜態多態和動態多態兩類不難。第一類也是函數重載,C++中多了一個運算符重載。派生類也就是子類繼承中重寫父類方法,又多了一個虛函數而已。

 

2. 靜態多態和動態多態區別:
靜態多態的函數地址早綁定-編譯階段確定函數地址
動態多態的函數地址晚綁定-運行階段確定函數的地址

這兩點區別,沒什麼解釋的,一個發生在編譯階段,一個發生在運行階段。

 

3.靜態綁定的代碼示例

先看看這段代碼,理解下什麼是靜態綁定

#include <iostream>
using namespace std;

//動物基類
class Animal{
public:
    void speak()
    {
        cout << "動物在叫" << endl;
    }
};

//貓類
class Cat : public Animal
{
public:
    void speak()
    {
        cout << "貓在叫" << endl;
    }
};

void doSpeak(Animal &animal)
{
    animal.speak();
}

void test01()
{
    Cat cat;
    doSpeak(cat);
}

int main()
{
    test01();
    system("pause");
}

在看運行結果之前,肯定會好奇,打印的是 “動物在叫” 還是貓在叫。在方法doSpeak中,參數是一個Animal的對象的引用。但是我們在test01中調用doSpeak()函數傳入的是一個cat對象。

看到上面輸出,輸出的Animal基類中的speak(), 現象是傳入的是一個派生類(Cat類)對象,執行的方法卻是基類的方法,這個就是動態綁定,在編譯階段,編譯器就把這個標記爲執行基類中的speak()方法,所以輸出調用的是基類中的speak方法。

本意上我們創建一個貓對象,應該是想打印“貓在叫”。也就是我們不希望進行靜態綁定,而是進行動態綁定,也就是在運行的時候,動態綁定函數地址,調用派生類中方法,下面使用virtual來實現動態綁定。

 

4.虛函數實現動態綁定

這裏虛函數就是在基類中成員函數前面加上關鍵字virtual,這個函數就叫虛函數。

#include <iostream>
using namespace std;

//動物基類
class Animal{
public:
    //虛函數實現動態綁定
    virtual void speak()
    {
        cout << "動物在叫" << endl;
    }
};

//貓類
class Cat : public Animal
{
public:
    void speak()
    {
        cout << "貓在叫" << endl;
    }
};

void doSpeak(Animal &animal)
{
    animal.speak();
}

void test01()
{
    Cat cat;
    doSpeak(cat);
}

int main()
{
    test01();
    system("pause");
}

就添加了一個virtual關鍵字,讓speak函數變成虛函數,輸出的結果卻是 “貓在叫”。

在test01函數中doSpeak(xx),在編譯的時候不能進行靜態綁定,確定函數地址。而是需要在運行的時候,根據傳入的參數,例如這裏是貓,或者傳入的是狗,它就會動態去找貓裏面的speak函數或狗中的speak函數,這個就叫動態搬綁定,動態確定函數speak()的地址。

總結:
動態多態滿足條件
1)有繼承關係
2)子類重寫父類的虛函數

動態多態的使用:

父類的指針或引用,指向子類對象。在上面代碼doSpeak(Animal &animal) 相當於 Animal & animal = cat; 當前還沒有用指針寫一個例子,後面學習。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章