国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁(yè) > 學(xué)院 > 開(kāi)發(fā)設(shè)計(jì) > 正文

三談多態(tài)——善用virtual

2019-11-18 18:41:00
字體:
來(lái)源:轉(zhuǎn)載
供稿:網(wǎng)友
 

三談多態(tài)——善用virtual

作者:Nicrosoft(nicrosoft@sunistudio.com) —— 2002.4.30

出處:東日軟件開(kāi)發(fā)網(wǎng)絡(luò)(SSDN) http://www.ssdn.net

 
  多態(tài)性,是一種能給程序帶來(lái)靈活性的東西。看過(guò)《設(shè)計(jì)模式》的程序員應(yīng)該都知道,相當(dāng)多的模式(幾乎所有)都是依靠多態(tài)來(lái)實(shí)現(xiàn)的,以此給程序提供可擴(kuò)展、可重用性。在《再談多態(tài)——向上映射及VMT/DMT》一文中,提到了多態(tài)性是依賴于虛函數(shù)/虛方法(即動(dòng)態(tài)綁定)來(lái)實(shí)現(xiàn)的,也介紹了虛函數(shù)/虛方法(virtual)的實(shí)現(xiàn)方法。那么本文就來(lái)談一下,如何使用virtual、善用virtual來(lái)獲取多態(tài)性給我們帶來(lái)的靈活性。
  
  實(shí)例是最好的教材,因此本文還是假設(shè)一個(gè)需求,寫一個(gè)實(shí)例來(lái)講解。不過(guò),我想沒(méi)有必要給出所有源碼,因此在本文中有些實(shí)現(xiàn)的代碼會(huì)粗略帶過(guò)。另外,本文所有代碼均為Object Pascal語(yǔ)言編寫,實(shí)現(xiàn)環(huán)境為Delphi。
  
  另外,由于“方法(Method)”一詞已經(jīng)成為Object Pascal的術(shù)語(yǔ),因此,以下稱成員函數(shù)都為“方法”。也許C++程序員會(huì)不太適應(yīng)這樣的稱呼(呵呵,我自己也不太適應(yīng)),見(jiàn)諒吧。
  
  假設(shè)我們要編寫一個(gè)純文本內(nèi)的編輯器,也就是記事本(呵呵,別嫌例子老套,記事本程序在相當(dāng)多方面都是很好的教材),編輯控件我們一般會(huì)用TMemo或TRichEdit,但是它們的功能都不甚強(qiáng)大,也許我們目前沒(méi)有,但日后會(huì)找到一個(gè)更好的第三方文本編輯控件(比如,支持語(yǔ)法著色的)。因此,我們必須為未來(lái)的改進(jìn)留下方便之門,否則到時(shí)候再重寫全部程序真是太傻了。
  
  界面層(菜單響應(yīng)、狀態(tài)顯示等)對(duì)文本編輯器控件的控制的代碼對(duì)于所有編輯器來(lái)說(shuō)都是類似的,應(yīng)該可以被重用。那么就必須將界面層的代碼與編輯器控件的控制代碼隔離開(kāi)來(lái)。
  
  如何隔離?我們可以為所有的編輯器控件指定一個(gè)公共的接口(抽象類),界面層只看得到這個(gè)接口,只使用接口提供的功能,那么,我們更換任何編輯器控件時(shí),都不必更改界面層的代碼了。
  
  首先,抽象出編輯器的基本操作,如:Load(打開(kāi)文本)、Save(保存到文件)、Copy(復(fù)制到剪貼板)等等,將這些操作作為public方法。其次,考慮這些操作中有哪些會(huì)涉及到具體相關(guān)控件的,對(duì)于這些操作,你有兩種選擇:1、如果完全依賴控件本身的,可以選擇將其定義為虛方法或抽象虛方法(即C++中的純虛函數(shù));2、如果只是有部分代碼依賴控件本身的,將這部分操作抽象到一個(gè)PRotected的抽象虛方法中,而將相同的部分代碼寫在基類中,并由基類的方法中調(diào)用protected的抽象虛方法。
  
  如果還沒(méi)有完全明白,請(qǐng)看代碼:
   
    TEditor = class // 抽象基類
  private
      m_FileName : String;
  protected
      function DoLoad(FileName : String) : Boolean; virtual; abstract;
    public
        function Load(FileName : String) : Boolean;
        function Save() : Boolean;
        function SaveAs(FileName : String) : Boolean; virtual; abstract;
      // ... 其他需要的操作,由需求而定
    end;
  
  好,我們來(lái)詳細(xì)說(shuō)明一下TEditor為什么是這個(gè)樣子的。其有一個(gè)私有成員,保存編輯器所對(duì)應(yīng)的文件名。然后看public部分,它至少提供了三個(gè)操作:Load——從某文件中讀取文本到編輯器;Save——將文本保存到文件,文件名為m_FileName所保存的;SaveAs——以指定的一個(gè)文件名保存文本。

  三個(gè)操作中,SaveAs為抽象虛方法,因?yàn)樗膶?shí)際動(dòng)作與每個(gè)編輯控件相關(guān),而基類本身并不知道該如何保存文件。

  Save和Load都是非虛方法,其中Save的任務(wù)很簡(jiǎn)單,就是將文本以m_FileName所保存的文件名保存,其實(shí)現(xiàn)可以是調(diào)用抽象的SaveAs,只需要將文件名傳給SaveAs即可。基類完全可以確定如何完成Save(因?yàn)樗梢员WC派生類實(shí)現(xiàn)了SaveAs),因此其為非虛方法。

  而Load呢?Load操作的步驟是:1、將文本從文件中讀取到編輯器控件中;2、將m_FileName的值設(shè)置為所讀取的文件名。其中第一個(gè)步驟與具體編輯器控件相關(guān),應(yīng)該是由派生類去實(shí)現(xiàn)它,第二個(gè)步驟派生類無(wú)法實(shí)現(xiàn),因?yàn)榕缮惪床坏剿接械膍_FileName成員。但即使把m_FileName移到protected節(jié)中,以使派生類可以訪問(wèn)它,也并非好辦法,因?yàn)檫@樣的話,在實(shí)現(xiàn)每個(gè)派生類時(shí),都要記住設(shè)置m_FileName的值,這不僅造成代碼重復(fù)(每個(gè)派生類都要這樣做),而且這不應(yīng)該是派生類的義務(wù)。因?yàn)閙_FileName應(yīng)該是基類的內(nèi)部實(shí)現(xiàn),對(duì)外不可見(jiàn)。因此,第二個(gè)步驟應(yīng)該由基類來(lái)完成。如何達(dá)成這個(gè)目的呢?

  我們可以注意到,protected節(jié)中有一個(gè)DoLoad方法,它就被用來(lái)完成第一個(gè)步驟——每個(gè)編輯器控件去將文本讀入編輯器。然后,DoLoad由Load方法中被選擇在適當(dāng)?shù)臅r(shí)機(jī)調(diào)用。
  
    基類的實(shí)現(xiàn)如下:

    function TEditor.Load(FileName : String) : Boolean;
  begin
      Result := DoLoad(FileName);
      if Result then
          m_FileName := FileName;
    end;
  
    function TEditor.Save() : Boolean;
  begin
      SaveAs(m_FileName); // 調(diào)用抽象的 SaveAs
    end;
  
  接著,我們使用TMemo來(lái)實(shí)現(xiàn)一個(gè)編輯器類:
  
  TMemoEditor = class(TEditor)
  private
      m_Editor : TMemo;
  protected
      function DoLoad(FileName : String) : Boolean; override;
    public
      constructor Create();
      destrcutor Destroy(); override;
  
      function SaveAs(FileName : String) : Boolean; override;
      // ...其它需要的操作
  end;
  
  在該派生類中,有一個(gè)私有成員,即TMemo控件的實(shí)例。然后覆蓋(override)了基類的兩個(gè)抽象虛方法:DoLoad和Save。
  
  其實(shí)現(xiàn)如下:
  function TMemoEditor.Create();
  begin
      // 創(chuàng)建TMemo實(shí)例
        m_Editor := TMemo.Create(nil);
     
        // 接著完成將TMemo實(shí)例置于界面上顯示出來(lái)等操作,省略
    end;
  
  function TMemoEditor.Destroy();
  begin
      // 其他清理工作
  
      m_Editor.Free();
      m_Editor := nil;
  end;
  
  function TMemoEditor.DoLoad(FileName : String) : Boolean;
  begin
        Result := false;
        try
          m_Editor.LoadFromFile(FileName);
       except end;
      Result := true;
  end;
  
  function TMemoEditor.SaveAs(FileName : String) : Boolean;
  begin
      Result := false;
      try
          m_Editor.SaveToFile(FileName);
      except end;
      Result := true;
    end;
  
  很好,這樣的實(shí)現(xiàn)已經(jīng)可以使個(gè)部分運(yùn)作正常了。如果,今后找到更好的編輯器控件,只需要從TEditor派生,再實(shí)現(xiàn)一個(gè)TXXXEditor類即可,其他部分的代碼不用作任何改動(dòng)。而且,具體實(shí)現(xiàn)的TXXXEditor類中的代碼,只和具體控件本身特性相關(guān)(如:讀取、保存文件的方法),而公共邏輯也已經(jīng)在TEditor類中實(shí)現(xiàn)了。
  
  virtual的使用方法,基于筆者個(gè)人認(rèn)識(shí)與經(jīng)驗(yàn):
  
  1、如果基類不知道如何實(shí)現(xiàn)某方法(只有派生類知道),而基類的其他方法又必須使用該方法,則把該方法聲明為抽象虛方法—— virtual; abstract;(即C++的純虛函數(shù))。
  
  2、如果基類能夠?yàn)槟撤椒ㄌ峁┮环N默認(rèn)實(shí)現(xiàn),但派生類可能完全重寫這個(gè)實(shí)現(xiàn),則將該方法聲明為虛方法—— virtual;并實(shí)現(xiàn)默認(rèn)算法。

  3、如果基類能夠且必須提供某方法的部分的實(shí)現(xiàn),而派生類必須提供另一部份的實(shí)現(xiàn),則將該方法聲明為非虛方法,并在基類中為其配套提供一個(gè)虛方法或抽象虛方法,以允許由基類本身調(diào)用和被派生類覆蓋。猶如上例中的Load與DoLoad。
  
  善用virtual,善用多態(tài),你的代碼將更具靈活性!


上一篇:讓彈出式廣告就地正法

下一篇:流操作的語(yǔ)法

發(fā)表評(píng)論 共有條評(píng)論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
學(xué)習(xí)交流
熱門圖片

新聞熱點(diǎn)

疑難解答

圖片精選

網(wǎng)友關(guān)注

主站蜘蛛池模板: 敖汉旗| 宽甸| 雅江县| 兰州市| 鄢陵县| 辛集市| 新乡县| 铜鼓县| 尚义县| 浦东新区| 句容市| 巴中市| 中牟县| 固镇县| 蓬溪县| 三原县| 通州市| 甘谷县| 屏边| 清原| 龙游县| 河津市| 新竹市| 海原县| 德安县| 读书| 丹寨县| 辽中县| 简阳市| 张掖市| 无棣县| 康乐县| 方正县| 滕州市| 宣威市| 芦溪县| 安岳县| 潮州市| 萝北县| 汶川县| 榆林市|