訪問祖先類的虛方法

2021-08-22 10:56:09 字數 3193 閱讀 6257

在子類覆蓋的虛方法中,可以用inherited呼叫父類的實現,但有時候我們並不需要父類的實現,而是想躍過父類直接呼叫祖先類的方法。

舉個例子,假設有三個類,實現如下:

type

tclassa = class

procedure proc; virtual;

end;

tclassb = class(tclassa)

procedure proc; override;

end;

tclassc = class(tclassb)

procedure proc; override;

end;

implementation

procedure tclassa.proc;

begin

showmessage('proc of class a');

end;

procedure tclassb.proc;

begin

showmessage('proc of class b');

end;

procedure tclassc.proc;

begin

showmessage('proc of class c');

end;

用如下**呼叫虛方法proc:

varc: tclassa;

begin

c := tclassc.create;

c.proc;

c.free;

end;

我們知道最終呼叫的是tclassc.proc;如果在tclassc.proc中加上inherited,則tclassb.proc可以得到呼叫;但是現在,若想在tclassc.proc中直接呼叫tclassa.proc,該怎麼辦呢?

如果是c++,只需要這樣寫:tclassc::proc。

在delphi卻沒有辦法做到,delphi不允許我們躍級呼叫祖先類的方法。儘管如此,還是能從另乙個角度來尋求解決的辦法。

解決之道就是vmt,每乙個類就是乙個指向vmt的指標,而vmt的作用其實就是用來儲存虛方法的。在vmt的正方向上,列著從祖先類起的所有虛方法,只需要偏移tclassa的vmt到proc,然後呼叫之即可。

來看看這個問題是怎麼得解決的:

procedure tclassc.proc;

type

tproc = procedure of object;

varm: tmethod;

begin

m.code := ppointer(tclassa)^;

m.data := self;

tproc(m)();

showmessage('proc of class c');

end;

執行一次呼叫,可以看到先彈出:proc of class a;然後彈出:proc of class c。這說明tclassa.proc在tclassc.proc中被呼叫到了。

請注意上面的**,tclassa的vmt上的第0偏移就是proc的位址,而tclassa繼承自tobject,tobject本身也有一些虛方法的,比如afterconstruction,那麼這些是存放在**呢?

秘密就在vmt的負偏移上,在system單元中宣告了虛表的結構偏移,在負方向上有afterconstruction的進入點。需要指出的是,system單元中宣告了結構偏移正方向的幾個已經過時了,第0偏移(vmtqueryinte***ce)不是存放queryinte***ce,而是存放第乙個虛方法(除tobject外)。

下面是從幫助上拷下來的vmt布局:

offset type description

-76 pointer pointer to virtual method table (or nil)

-72 pointer pointer to inte***ce table (or nil)

-68 pointer pointer to automation information table (or nil)

-64 pointer pointer to instance initialization table (or nil)

-60 pointer pointer to type information table (or nil)

-56 pointer pointer to field definition table (or nil)

-52 pointer pointer to method definition table (or nil)

-48 pointer pointer to dynamic method table (or nil)

-44 pointer pointer to short string containing class name

-40 cardinal instance size in bytes

-36 pointer pointer to a pointer to ancestor class (or nil)

-32 pointer pointer to entry point of safecallexception method (or nil)

-28 pointer entry point of afterconstruction method

-24 pointer entry point of beforedestruction method

-20 pointer entry point of dispatch method

-16 pointer entry point of defaulthandler method

-12 pointer entry point of newinstance method

-8 pointer entry point of freeinstance method

-4 pointer entry point of destroy destructor

0 pointer entry point of first user-defined virtual method

4 pointer entry point of second user-defined virtual method

利用虛表呼叫虛方法的做法,終究不是安全的,因為borland(codegear)沒有向你保證每乙個delphi版本的vmt布局都是一樣的。

因此,使用這個方法的時候要慎之又慎。

C 類的繼承 訪問許可權 虛繼承

今天突然發現自己關於類的繼承,虛基類,訪問許可權混在在一起的時候有有一些模糊,所以今天進行重新學習一下。如果錯誤或者不對的地方,還請指教。一 類的繼承方式 類有三種成員成員,private,protected,public,基類的成員 派生方式 子類訪問特性 public protected pri...

訪問類的方法和屬性

using system using system.reflection using system.collections.generic using system.runtime.compilerservices class example set private int instanceprop...

C 巢狀類的訪問方法

對於以下資料,如何在執行時通過字串來得程式設計客棧到靜態變數uipath的值。複製 如下 public class ga程式設計客棧memainmenu uiclass 像下面這樣即可。複製 如下 bindingflags flag bindingflags.static bindingflags....