溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

C++語言學(xué)習(xí)(十一)——多態(tài)

發(fā)布時間:2020-07-11 06:58:43 來源:網(wǎng)絡(luò) 閱讀:1115 作者:天山老妖S 欄目:編程語言

C++語言學(xué)習(xí)(十一)——多態(tài)

一、多態(tài)簡介

C++中的多態(tài)(polymorphism)是指由繼承而產(chǎn)生的相關(guān)的不同的類,其對象對同一消息會作出不同的響應(yīng)。
多態(tài)性是面向?qū)ο蟪绦蛟O(shè)計的一個重要特征,能增加程序的靈活性??梢詼p輕系統(tǒng)升級,維護(hù),調(diào)試的工作量和復(fù)雜度。
多態(tài)是一種不同層次分類下的重要聯(lián)系,是一種跨層操作。

二、多態(tài)實現(xiàn)的前提

賦值兼容規(guī)則是指在需要基類對象的任何地方都可以使用公有派生類的對象來替代。
賦值兼容是一種默認(rèn)行為,不需要任何的顯式的轉(zhuǎn)化步驟,只能發(fā)生在public繼承方式中,是多態(tài)實現(xiàn)的前提條件。
賦值兼容規(guī)則中所指的替代包括以下的情況:
A、子類對象可以直接賦值給父類對象
B、子類對象可以直接初始化父類對象
C、父類引用可以直接引用子類對象
D、父類指針可以直接指向子類對象
當(dāng)使用父類指針(引用)指向子對象時,子類對象退化為父類對象,只能訪問父類中定義的成員,可以直接訪問被子類覆蓋的同名成員。

#include <iostream>
using namespace std;

class Parent
{
public:
    int m;
    Parent(int a)
    {
        m = a;
    }
    void print()
    {
        cout << "Parent m = " << m << endl;
    }
};

class Child : public Parent
{
public:
    int m;
    Child(int a):Parent(a)
    {
        m = a;
    }
    void print()
    {
        cout << "Child m = " << m << endl;
    }
};
int main()
{
    Parent p(0);
    Child c(0);
    Parent p1(c);
    Parent* pp = &c;//指向子類對象的父類指針退化為父類對象
    Parent& rp = c;//指向子類對象的父類引用退化為父類對象
    pp->print(); //Parent m = 0
    rp.print(); //Parent m = 0
    //Child cc = static_cast<Child>(p);//需要轉(zhuǎn)換構(gòu)造函數(shù)支持
    Child* pc = static_cast<Child*>(&p);
    pc->print();//Child m = xxxx
    return 0;
}

在替代后,派生類對象就可以作為基類的對象使用,但只能使用從基類繼承的成員。
父類也可以通過強(qiáng)轉(zhuǎn)的方式轉(zhuǎn)化為子類,但存在訪問越界的風(fēng)險。
子類中可以重定義父類中已經(jīng)存在的成員函數(shù),即函數(shù)重寫。
當(dāng)函數(shù)重寫遇到賦值兼容時,編譯器只能根據(jù)指針的類型判斷所指向的對象,根據(jù)賦值兼容原則,編譯器認(rèn)為父類指針指向的是父類對象,只能調(diào)用父類中定義的同名函數(shù)。
面向?qū)ο缶幊讨?,通常需要根?jù)實際的對象類型判斷如何調(diào)用重寫函數(shù)。當(dāng)父類指針指向父類對象,則調(diào)用父類定義的函數(shù);當(dāng)父類指針指向的是子類對象時,需要調(diào)用子類定義的函數(shù);當(dāng)父類引用對父類對象進(jìn)行引用時,調(diào)用父類對象定義的函數(shù);當(dāng)父類引用對子類對象進(jìn)行引用時,調(diào)用子類定義的函數(shù)。

三、多態(tài)形成的條件

1、多態(tài)形成的條件

根據(jù)父類指針指向的實際對象類型決定調(diào)用的函數(shù),即多態(tài)。多態(tài)中,父類指針(引用)指向父類對象則調(diào)用父類中定義的函數(shù),父類指針(引用)指向子類對象時調(diào)用子類對象的函數(shù)。
C++通過virtual關(guān)鍵字對多態(tài)進(jìn)行支持,被virtual聲明的函數(shù)被重寫后具有多態(tài)屬性。
多態(tài)形成的條件:
A、父類中有虛函數(shù)。
B、子類override(覆寫)父類中的虛函數(shù)。
C、通過己被子類對象賦值的父類指針,調(diào)用共用接口。

2、虛函數(shù)

虛函數(shù)的聲明語法如下:

virtual 函數(shù)聲明;

虛函數(shù)的使用規(guī)則如下:
A、在父類中用 virtual 聲明成員函數(shù)為虛函數(shù)。類外實現(xiàn)虛函數(shù)時,不必再加virtual。
B、在派生類中重定義父類中已經(jīng)存在的成員函數(shù)稱為函數(shù)覆寫,要求函數(shù)名,返值類型,函數(shù)參數(shù)個數(shù)及類型全部匹配,并根據(jù)派生類的需要重新定義函數(shù)體。
C、當(dāng)一個成員函數(shù)被聲明為虛函數(shù)后,其派生類中完全相同的函數(shù)也為虛函數(shù),派生類中的虛函數(shù)可以加virtual關(guān)鍵字,也可以不加。
D、定義一個父類對象指針,使其指向其子類的對象,通過父類指針調(diào)用虛函數(shù),此時調(diào)用的是子類的同名函數(shù)。
E、構(gòu)造函數(shù)不能為虛函數(shù),在構(gòu)造函數(shù)執(zhí)行完畢后虛函數(shù)表指針才能被正確初始化。析構(gòu)函數(shù)可以為虛函數(shù),定義一個父類指針并使用new創(chuàng)建的子類對象初始化,使用delete釋放父類指針的堆空間時,只會調(diào)用父類的析構(gòu)函數(shù),不會調(diào)用子類的析構(gòu)函數(shù),會造成內(nèi)存泄漏,父類析構(gòu)函數(shù)聲明為虛函數(shù)可以避免該問題。一般來說需要將析構(gòu)函數(shù)聲明為虛函數(shù)。構(gòu)造函數(shù)執(zhí)行時,虛函數(shù)表指針未被正確初始化,因此構(gòu)造函數(shù)不可能發(fā)生多態(tài);析構(gòu)函數(shù)函數(shù)執(zhí)行時,虛函數(shù)表指針已經(jīng)被銷毀,因此析構(gòu)函數(shù)也不可能發(fā)生多態(tài)。構(gòu)造函數(shù)和析構(gòu)函數(shù)中只能調(diào)用當(dāng)前類中定義的函數(shù)版本。

#include <iostream>

using namespace std;

class Parent
{
public:
    int mi;
    void add(int i)
    {
        mi += i;
    }
    void add(int a, int b)
    {
        mi += (a + b);
    }
    virtual void print()
    {
        cout << "Parent" << endl;
    }
};

class Child : public Parent
{
public:
    int mi;
    //函數(shù)重寫
    void add(int x, int y)
    {
        mi += (x + y);
    }
    //函數(shù)重寫
    void print()
    {
        cout << "Child" << endl;
    }
};

int main(int argc, char *argv[])
{
    Child child;
    child.add(1,2);//調(diào)用子類函數(shù)
    child.Parent::add(1);//調(diào)用父類函數(shù)
    child.Parent::add(1,2);//調(diào)用父類函數(shù)
    Parent p = child;
    p.add(1);
    p.add(1,2);
    Parent& rp = child;
    rp.add(1);
    rp.add(1,2);
    rp.print();//Child

    Parent* pp = &child;
    pp->add(1);
    pp->add(1,2);
    pp->print();//Child

    return 0;
}

3、純虛函數(shù)

純虛函數(shù)的聲明語法如下:

virtual 函數(shù)聲明 = 0;

純虛函數(shù)的使用規(guī)則如下:
A、含有純虛函數(shù)的類,稱為抽象基類,不可實例化,即不能創(chuàng)建對象,存在的意義就是被繼承,提供類族的公共接口,Java中稱為 interface。
B、純虛函數(shù)只有聲明,沒有實現(xiàn)。
C、如果一個類中聲明了純虛函數(shù),而在派生類中沒有對純虛函數(shù)進(jìn)行實現(xiàn),則該虛函數(shù)在派生類中仍然為純虛函數(shù),派生類仍然為抽象基類。

4、虛函數(shù)的使用規(guī)則

虛函數(shù)的使用規(guī)則如下:
A、只有類的成員函數(shù)才能聲明為虛函數(shù)。虛函數(shù)僅適用于有繼承關(guān)系的類對象,所以普通函數(shù)不能聲明為虛函數(shù)。
B、靜態(tài)成員函數(shù)不能是虛函數(shù)。靜態(tài)成員函數(shù)不受對象的捆綁,只有類的信息。
C、內(nèi)聯(lián)函數(shù)不能是虛函數(shù)。
D、構(gòu)造函數(shù)不能是虛函數(shù)。構(gòu)造時,對象的創(chuàng)建尚未完成。構(gòu)造完成后,才能算一個名符其實的對象。
E、析構(gòu)函數(shù)可以是虛函數(shù)且通常聲明為虛函數(shù)
F、含有虛函數(shù)的類,析構(gòu)函數(shù)也必須聲明為虛函數(shù)。在delete父類指針的時候,會調(diào)用子類的析構(gòu)函數(shù)。

四、多態(tài)的意義

多態(tài)的意義如下:
A、在程序運行過程中展現(xiàn)出的動態(tài)特性
B、函數(shù)重寫必須多態(tài)實現(xiàn),否則沒有意義
C、多態(tài)是面向?qū)ο蠼M件化程序設(shè)計的基礎(chǔ)特性
D、多態(tài)是一種跨層操作
靜態(tài)聯(lián)編是在程序的編譯期間就能確定具體的函數(shù)調(diào)用,如函數(shù)重載。
動態(tài)聯(lián)編是在程序?qū)嶋H運行時才能確定具體的函數(shù)調(diào)用,如函數(shù)重寫。

#include <iostream>

using namespace std;

class Parent
{
public:
    int mi;
    virtual void add(int i)
    {
        mi += i;
    }
    virtual void add(int a, int b)
    {
        mi += (a + b);
    }
    virtual void print()
    {
        cout << "Parent" << endl;
    }
};

class Child : public Parent
{
public:
    int mi;
    //函數(shù)重寫
    void add(int x, int y)
    {
        mi += (x + y);
    }
    //函數(shù)重寫
    void print()
    {
        cout << "Child" << endl;
    }
};

int main(int argc, char *argv[])
{
    Child child;
    child.add(1,2);//靜態(tài)聯(lián)編
    child.Parent::add(1);//靜態(tài)聯(lián)編
    child.Parent::add(1,2);//靜態(tài)聯(lián)編
    Parent p = child;
    p.add(1);//靜態(tài)聯(lián)編
    p.add(1,2);//靜態(tài)聯(lián)編
    p.print();//靜態(tài)聯(lián)編
    cout << endl;
    Parent& rp = child;
    rp.add(1);//靜態(tài)聯(lián)編
    rp.add(1,2);//動態(tài)聯(lián)編
    rp.print();//動態(tài)聯(lián)編

    Parent* pp = &child;
    pp->add(1);//靜態(tài)聯(lián)編
    pp->add(1,2);//動態(tài)聯(lián)編
    pp->print();//動態(tài)聯(lián)編

    return 0;
}
向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進(jìn)行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI