操屁眼的视频在线免费看,日本在线综合一区二区,久久在线观看免费视频,欧美日韩精品久久综

新聞資訊

    多態(tài)是面向?qū)ο笤O(shè)計中的無法避免的重要概念,有什么接地氣的解讀方法嗎?


    01

    提出問題

    多態(tài)可能是C++里面,最重要的設(shè)計技巧。用到了多種語法規(guī)則,例如:類型轉(zhuǎn)換、虛函數(shù)、繼承、函數(shù)重載等。如果不了解多態(tài),可能C++語法倒背如流,都意義不大。今天,讓我們用CPU的視角,重新認識一下:多態(tài)。


    02

    代碼分析

    打開Compiler Explorer,寫一個最簡單類A;再編寫一個最簡單的派生類B;先寫一個符合多態(tài)原則的函數(shù)func1,用基類指針變量 p 指向 派生類對象 b,如圖所示。

    很合理,編譯也很順利。讓我們再寫一個違反多態(tài)原則的函數(shù)func2,也就是用派生類指針 p 指向 基類對象 a,如圖所示。

    不出意外,因為不符合多態(tài)原則,編譯器報錯。為了通過編譯,我們強制轉(zhuǎn)換一下,如圖所示。

    好了,編譯順利通過。而且,兩個函數(shù)的匯編指令也完全相同!其實,CPU對多態(tài)是無感的。在阿布看來,這個階段的多態(tài),不過是一種合法的類型轉(zhuǎn)換而已。

    其實,你也可以把派生類B,轉(zhuǎn)換成任何類型,這里,舉一個極端的例子。比如,我們寫個函數(shù)func3,作一個向 int 類型的轉(zhuǎn)換,如圖所示。

    不僅編譯通過,匯編指令也跟函數(shù)func1、函數(shù)func2完全一致。

    好了,回到正題。如果多態(tài)是一種合法的類型轉(zhuǎn)換的話;那么,什么是不合法的類型的轉(zhuǎn)換呢?

    答案是:無論哪種類型轉(zhuǎn)換,都是不安全的!只要作類型轉(zhuǎn)換,編譯器往往會發(fā)出警告,唯獨給多態(tài)(派生類向基類作指針轉(zhuǎn)換)開了一個特例。

    那這樣作,安全嗎?答案是:安全的,這要從類的數(shù)據(jù)結(jié)構(gòu)說起(基于32位的CPU)讓我們先看看基類A的結(jié)構(gòu),如圖所示。

    起始的4個字節(jié),分配給變量x;隨后的4個字節(jié),分配給變量y。如果有虛函數(shù)的話,x,y同時上移4個字節(jié),把起始的4個字節(jié),留給隱藏變量V,用于存放類A的虛函數(shù)表地址,如圖所示。

    然后,再看看派生類B的結(jié)構(gòu),如圖所示。

    首先把基類A的結(jié)構(gòu)全盤復(fù)制過來;如果有虛函數(shù),則隱藏變量V,改為類B的虛函數(shù)表地址;最后,在內(nèi)存地址的最高位增加4個字節(jié),分配給變量z。

    你發(fā)現(xiàn)有趣的事情了嗎?如果不考慮派生類B特有的變量z,派生類B的結(jié)構(gòu)跟基類A,是完全相同的。你完全可以把派生類B,降級成基類A來使用。

    而下面的func4,不正是把派生類B的對象,降級(類型轉(zhuǎn)換)成基類A的對象在使用嗎?

    void func4(B& b)
    {
      A* p=&b;
      p->x=1;
      p->y=2;
    }

    也就是常說的:代碼復(fù)用!相反,我們可以把基類A,升級成派生類B使用,可以嗎?如圖所示。


    顯然不行,如你所見:因為類A沒有給變量 z 預(yù)留空間。所以,即使函數(shù)func5能通過編譯,可一旦訪問變量z,就會越界!

    讀寫到不屬于變量a的內(nèi)存空間。隨后的情況,不是程序崩潰,就是運行異常。大家也可以參看CPU眼里的:數(shù)組越界,它們的原理是相似的。

    當然,如果多態(tài)僅僅只是把派生類降級成基類使用。就太沒有意思了,雖然復(fù)用了基類的共性,卻沒有體現(xiàn)出自己的特性。如何體現(xiàn)特性呢?答案是:虛函數(shù)。

    比如:我們要訪問類B的特有變量z,我們就可以定義一個這樣的虛函數(shù),如圖所示。

    至于類A,沒有特有變量 z,可以給它寫一個返回-1的空函數(shù)或純虛函數(shù)。

    如CPU眼里的:虛函數(shù)所講,如圖所示。

    根據(jù)動態(tài)綁定的實現(xiàn)原理,無論指針p是什么類型,當p指向類A的對象時,它就會調(diào)用類A特有的虛函數(shù);當p指向類B的對象時,它就會調(diào)用類B特有的虛函數(shù)。

    這也是多態(tài)的精髓:調(diào)用相同名稱的函數(shù),卻會根據(jù)對象的實際類型,執(zhí)行不同的函數(shù)版本。當軟件代碼變得越發(fā)復(fù)雜的時候,這種設(shè)計方法可以消滅掉大量的switch case語句。

    就這樣,類B的對象,不僅可以復(fù)用基類A的屬性(變量/函數(shù));還可以擴展自己的特性(變量z)


    03

    實例分析

    在現(xiàn)實世界中,最常見的多態(tài)設(shè)計就是:圖形界面(如圖所示:這是一個簡化的音樂播放器界面)

    我們在網(wǎng)頁、或手機APP上,看到的界面元素,往往都有一個共同的基類,負責一些基本功能,比如:記錄位置、大小、形狀信息,以及導(dǎo)航規(guī)則和提供:抽象、統(tǒng)一化的函數(shù)接口,如圖所示。

    同時,所有的界面元素也會根據(jù)自己的特性,重載一個虛函數(shù),用于繪制自己的外形,例如:draw。也就是繪制我們可以看到的:按鈕、標簽、開關(guān)、進度條,如圖所示。

    如果采用左邊的多態(tài)的設(shè)計方法,只需要一個虛函數(shù)接口draw,就可以統(tǒng)一所有界面元素的繪制函數(shù)接口;不同的界面元素,只需要根據(jù)自身特點,重載一下draw函數(shù)即可。

    而如果采用右邊的非多態(tài)設(shè)計方法,就需要在對界面元素,作差異化操作的時候(例如:繪制界面元素的外觀)使用switch case語句,手動的做好區(qū)分工作,讓不同的界面元素,調(diào)用與之適應(yīng)的繪制函數(shù)。

    雖然都能實現(xiàn)功能,但哪種方法更清晰,更容易維護和擴展呢?


    04

    總結(jié)

    1. 多態(tài),常會用基類指針,指向派生類對象。

    2. 多態(tài),會利用派生類的結(jié)構(gòu)特點,復(fù)用基類的屬性(變量/函數(shù))

    3. 多態(tài),會利用虛函數(shù),來擴展派生類的特性。

    最后,多態(tài)不是C++的專利,很多語言都支持多態(tài),例如:Java。與其說多態(tài)是:語法規(guī)則,不如說是:設(shè)計技巧。

    如何準確的區(qū)分:共性、特性;需要根據(jù)自己的具體情況,具體分析。僅僅用CPU的視角看待多態(tài),是非常局限、片面的。


    05

    熱點問題

    Q1:類B使用類A的屬性、方法,這不就是繼承嗎?為什么跟多態(tài)扯上關(guān)系了呢?

    A1:多態(tài)使用了很多語法功能,包括了:繼承,類型轉(zhuǎn)換,虛函數(shù),函數(shù)重載等。我們或許不能把多態(tài)當作某種語法規(guī)則,多態(tài)更像是一種設(shè)計技巧,有了C++的加持,會讓開發(fā)者更加優(yōu)雅的實現(xiàn)多態(tài)的設(shè)計構(gòu)想。


    06

    更多知識

    如果喜歡阿布這種解讀方式,希望更加系統(tǒng)學(xué)習(xí)這些編程知識的話,也可以考慮看看由阿布親自編寫,并有多位微軟大佬聯(lián)袂推薦的新書《CPU眼里的C/C++》

網(wǎng)站首頁   |    關(guān)于我們   |    公司新聞   |    產(chǎn)品方案   |    用戶案例   |    售后服務(wù)   |    合作伙伴   |    人才招聘   |   

友情鏈接: 餐飲加盟

地址:北京市海淀區(qū)    電話:010-     郵箱:@126.com

備案號:冀ICP備2024067069號-3 北京科技有限公司版權(quán)所有