日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

Delphi面向对象学习随笔六:接口

發(fā)布時間:2025/3/15 编程问答 16 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Delphi面向对象学习随笔六:接口 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
Delphi面向?qū)ο髮W(xué)習(xí)隨筆六:接口

?
Delphi面向?qū)ο髮W(xué)習(xí)隨筆六:接口
作者:巴哈姆特
(轉(zhuǎn)載請注明出處并保持完整)

在對象化中,類的繼承是一個非常強大的機制;而更加強大的繼承機制應(yīng)該是來自從一個接口的繼承。
??? 本篇我們將討論接口的特點。
??? 首先,接口的定義方式與類相似。不同的是:類代表了一種實體,而接口代表了一批操作規(guī)范。還有,接口中所有的數(shù)據(jù)成員都是public訪問限制,也就是說,你不能為接口中的數(shù)據(jù)成員指定其為私有或其他的域成員。另外,接口中的方法只能有聲明而不能有實現(xiàn),因此它看上去更像是一個沒有構(gòu)造和析構(gòu)方法的純虛類。
??? 我看的很多資料中,凡是在介紹接口的時候都會提到“多重繼承”,仿佛接口的存在只是為了彌補Object Pascal不支持多重繼承而設(shè)計的(至少給我的第一印象就是這樣),其實接口是非常強大的,也是對象化編程中不可或缺的一個重要組成部分。
??? 接口之所以強大在于:接口只需要告訴用戶方法的名稱是什么,有什么參數(shù);而它并不需要理會方法是怎么實現(xiàn)的。例如電腦的構(gòu)造和工作方式對于一般用戶并不重要,因為一般用戶更關(guān)心的是如何去使用他。所以電腦的接口——鼠標(biāo)、鍵盤、顯示器等才是用戶最關(guān)心的地方。那么這就為我們實現(xiàn)對象化最核心的理念——“分離”提供了相當(dāng)大的便捷。

??? 首先我們來看看接口的定義方式:下面是Delphi中System.pas里IInterface接口的聲名方式

type
? IInterface = interface
??? ['']
??? function QueryInterface(const IID: TGUID; out Obj): HResult; stdcall;
??? function _AddRef: Integer; stdcall;
??? function _Release: Integer; stdcall;
? end;

我們可以看到,和類的基本聲明差不多,只是由關(guān)鍵字class改成了interface。
??? 大家也許會注意到在緊跟在聲明后的[''],這是什么呢?這是其實是接口的唯一標(biāo)識,也就是我們說的TGUID;當(dāng)把接口注冊給系統(tǒng)后,我們可以通過注冊表檢索到00000000-0000-0000-C000-000000000046這樣的鍵值。那么這就意味著,我們只需要知道一個TGUID的值就可以方便的訪問這個接口。
??? 當(dāng)然,你可以在接口中定義其他的方法,但是Delphi中是不允許給接口添加變量成員的,因為接口是不允許有實現(xiàn)部分的。

??? 同樣,接口也可以繼承、封裝以及方法的覆蓋。繼承接口同類繼承類似:

type
? INewInterface = interface(IInterface)
??? // 定義一個新的接口INewInterface,并告訴編譯器它是繼承自IInterface接口
??? ....
? end;

這里要注意一點,就是我們說過,接口的TGUID是每一個接口的唯一標(biāo)識,那么也就是說,TGUID是不能重復(fù)的。你不能簡單的從別處抄襲過來,那樣是錯誤的。如果你需要一個TGUID,你可以在Delphi的代碼編輯框中同時按下CTRL+SHIFT+G來獲得一個新的TGUID值,這個值是Delphi為你自動生成的。

??? 接口的繼承大致就是這樣,和TObject是所有類的根類一樣,在Delphi中IInterface是所有接口的根類,那么類似于下面的繼承:

type
? INewInterface = interface
??? ...
? end;

其實也是定義了一個繼承自IInterface的新接口INewInterface(和類名前加一個大寫字母T一樣,我們習(xí)慣于在接口名前加一個大寫字母I,當(dāng)然這只是一個命名約定)

??? 我們說了,接口只能有聲明,不能有實現(xiàn)。那么怎么讓接口為我們工作呢?
??? 其實,接口的實現(xiàn)是需要借助于類來完成的(當(dāng)然這看上去和C++中的多重繼承的寫法差不多)注意,既然接口是需要借助類來實現(xiàn)的,那么也就是說用來實現(xiàn)接口的類,必須實現(xiàn)接口中所有已定義的方法:

type
? TNewInterfaceClass = class(TInterfacedObject, INewInterface)
??? // TInterfacedObject為類名,INewInterface為我們上面定義的接口名
??? ...
? end;

一般,我們用來實現(xiàn)接口的基類不會選TObject而會選TInterfacedObject,理由是TInterfacedObject類已經(jīng)幫我們實現(xiàn)了IInterface接口中的方法,我們只需要實現(xiàn)我們自己接口中新的方法就可以了。

??? 既然我們已經(jīng)通過類實現(xiàn)了接口中的方法,那么我們就可以使用這個接口來為我們服務(wù)了,實例化接口也非常簡單:

var
? NewFace: INewInterface;
begin
? NewFace:= TNewInterfaceClass.Create(); // 創(chuàng)建接口
? NewFace.xxx; // 調(diào)用接口中的方法
? NewFace:= nil; // 釋放
end;

有朋友可能會奇怪,接口的釋放為什么只是直接賦為nil?我們前面說過了:接口即沒有構(gòu)造方法,也沒有析構(gòu)方法。既然沒有析構(gòu)方法,那么就意味著我們不能用釋放類的方式來釋放接口。
??? 那么直接把接口對象指空會造成內(nèi)存泄露嗎?
??? 答案是否定的,因為接口提供了一個引用記數(shù)的機制:當(dāng)某接口實例(也就是實現(xiàn)了這個接口的對象)被引用,比如被賦值給一個接口變量時,該接口實例的AddRef方法會被編譯器自動調(diào)用,引用計數(shù)將增加一。引用取消時編譯器則會調(diào)用_Release方法將引用計數(shù)減一。引用計數(shù)減到零時,表示已無其他接口變量引用此接口實例,此時編譯器會自動釋放它。

??? 要注意的是,接口對象與類對象是不能混用的。當(dāng)然像我們上面的例子里,NewFace也只能調(diào)用INewInterface接口中所定義過的方法,而不能調(diào)用類中定義的不存在于接口中的方法。

??? 當(dāng)然,一個類可以同時實現(xiàn)多個接口,多個接口彼此用逗號隔開。如:

type
? TNewInterfaceClass = class(TInterfacedObject, IInterface1, IInterface2)
? ...
? end;

同樣,實現(xiàn)多個接口的類必須依次實現(xiàn)每個接口中定義的方法。
??? 那么,這時出現(xiàn)了一個問題——就是當(dāng)兩個接口中有同名方法怎么辦?好辦,為他們?nèi)e名:

type
? IInterface1 = interface(IInterface)
??? // 接口1
??? fucntion Func(): Boolean;
? end;

? IInterface2 = interface(IInterface)
??? // 接口2
??? function Func(): Boolean;
? end;

? TClasses = class(TInterfacedObject, IInterface1, IInterface2)
? public
??? function IInterface1.Func: Func1;
??? function IInterface2.Func: Func2;
????? { 為同名方法起別名 }
??? function Func1: Boolean;
??? function Func2: Boolean;
????? { 聲明方法 }
? end;

Delphi中還可以使用imploements指示符用于委托另一個類或接口來實現(xiàn)接口的某個方法,有時這個方法又被稱為委托實現(xiàn),關(guān)于implements的用法如下:

type
? TInterClass = class(TInterfacedObject, IInterface1)
??? ...
??? function GetClasses: TClasses;
??? property Face: TClasses read GetClasses implements IInterface1;
??? ...
? end;

上面的代碼中,implements指示字會要求編譯器在Face屬性中尋找實現(xiàn)IInterface1接口的方法,屬性的類型必須是一個類或一個接口。implements可以指定多個接口,彼此用逗號分隔。

??? implements指示字的好處是:
??? 一、他允許以無沖突的方式進行接口聚合。(聚合是COM中的概念)
??? 二、他能夠延后占用實現(xiàn)接口所需要的資源,直到確實需要資源。

??? 下面是關(guān)于委托的一個詳細例子(該例在DELPHI7 + WIN2000 SP4 中調(diào)試通過):

? INewInterface = interface(IInterface)
??? // 定義接口
??? function SayHello: string; stdcall;
????? // 接口方法
? end;

? TNewClass = class(TInterfacedObject, INewInterface)
? public
??? function SayHello: string; stdcall;
????? // 第一個類實現(xiàn)接口中的方法
? end;

? TNewClass1 = class(TInterfacedObject, INewInterface)
? private
??? FNewClass: INewInterface;
? public
????? // 注意,在這個類中并沒有實現(xiàn)接口中的SyaHello方法
??? constructor Create;
??? destructor Destroy; override;
??? property NewClass: INewInterface read FNewClass implements INewInterface;
????? // 接口對象委托 如果是類對象委托應(yīng)該是
??? // property NewClass: TNewClass read FNewClass implements INewInterface;
? end;

implementation

function TNewClass.SayHello: string;
begin
? Result:= ClassName;
? ShowMessage(Result);
end;

constructor TNewClass1.Create;
begin
? inherited Create();
? FNewClass:= TNewClass.Create;
??? // 在構(gòu)造方法中創(chuàng)建接口
end;

destructor TNewClass1.Destroy;
begin
? FNewClass:= nil;
??? // 在析構(gòu)方法中釋放接口
? inherited Destroy();
end;

調(diào)用的例子:

var
? NewInterface: INewInterface;
begin
? NewInterface:= TNewClass1.Create;
? NewInterface.SayHello;
? NewInterface:= nil;
end;

題外話:如果你還沒有接觸過COM/COM+的話,也許你會認為接口十分麻煩(PS: 當(dāng)年我剛學(xué)的時候真想一腳把發(fā)明接口機制的人踹死),但是接口經(jīng)過COM的封裝后,將變的非常的有意義,呵呵!

總結(jié)

以上是生活随笔為你收集整理的Delphi面向对象学习随笔六:接口的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。