2012-05-30 220 views
2

我正在研究從商業組件套件派生的組件,並且遇到了一個我從未考慮過的挑戰。請看下面的代碼片段:從祖先的祖先繼承方法

TMyClass = class 
protected 
    procedure SomeMethod; virtual; 
end; 

TMyClass1 = class(TMyClass) 
protected 
    procedure SomeMethod; override; 
end; 

TMyMode = (mmOne, mmTwo); 
TMyClass2 = class(TMyClass1) 
private 
    FMode: TMyMode; 
protected 
    procedure SomeMethod; override; 
public 
    property Mode: TMyMode read FMode write FMode; 
end; 

... 

procedure TMyClass2.SomeMethod; 
begin 
    if FMode = mmOne then inherited SomeMethod 
        else inherited TMyClass.SomeMethod; 
end; 

所以,如果模式= mmOne然後我繼承是正常的,但如果它是mmTwo,我還是想繼承我的祖先的祖先的代碼,但是不知道是在祖先介紹。我已經嘗試了上述,但沒有成功,因爲我以前從未遇到過這種情況,所以我認爲這是不可能的。任何接受者?

+0

我不想成爲一個煞風景,但我寧願重新安排我的代碼因此這個構造的需求消失了 - 拆分一個或兩個方法,添加一個參數或其他東西。 –

+0

我同意 - 失去繼承時總是存在下游問題的危險。但是,我無法控制商業組件。我可以相應地更改他們的代碼,但每當我升級組件套件(DevExpress)時,都會給我帶來下游維護問題。對於這個特定的場景,我認爲這是最好的方法。 – Peter

回答

6

你可以用類傭工這樣做:

type 
    TA = class 
    public 
    procedure X; virtual; 
    end; 

    TB = class(TA) 
    public 
    procedure X; override; 
    end; 

    TA_Helper = class helper for TA 
    procedure A_X; 
    end; 

    TC = class(TB) 
    public 
    procedure X; override; 
    end; 

procedure TA.X; 
begin 
    // ... 
end; 

procedure TB.X; 
begin 
    // ... 
end; 

procedure TA_Helper.A_X; 
begin 
    inherited X; // TA.X 
end; 

procedure TC.X; 
begin 
    A_X; 
    inherited X; // TB.X 
end; 

我覺得在D2006中存在類的幫手,但如果他們不這樣做,你也可以使用一劈到一樣的效果:

// ... 
    TA_Helper = class(TA) 
    procedure A_X; 
    end; 
// ... 
procedure TC.X; 
begin 
    TA_Helper(Self).A_X; 
    inherited X; // TB.X 
end; 
+0

謝謝你,hvd。這已成爲世界上最好保守的祕密。你已經救了我幾個小時! – Peter

4

有沒有類助手或其他方法(如在@ hvd答案)這個任務的另一種解決方案。你可以得到基類方法的代碼地址和self數據指針調用它:
更新的代碼,沒有RTTI

unit Unit4; 

interface 
type 
    TA = class(TObject) 
     protected 
     procedure Test(); virtual; 
    end; 

    TB = class(TA) 
     protected 
     procedure Test(); override; 
    end; 

    TC = class(TB) 
     public 
     procedure Test(); override; 
    end; 

implementation 

procedure TA.Test; 
begin 
    writeln('TA.Test()'); 
end; 

procedure TB.Test; 
begin 
    writeln('TB.Test'); 
end; 

procedure TC.Test; 
var TATest : procedure of object; 
begin 
    writeln('TC.Test();'); 
    writeln('call inherited TB: '); 
    inherited Test(); 


    writeln('call inherited TA:'); 
    TMethod(TATest).Data := self; 
    TMethod(TATest).Code := @TA.Test; 
    TATest(); 
end; 
end. 
+0

當然TRTTIContext在d2006中不存在,但有一箇舊的rtti單元,您可以使用它來獲取指向「TA.Test」方法的代碼指針 – teran

+0

我不認爲您可以在D2006中使用RTTI訪問這些方法,所有,除非這些方法是「發佈」的。 – hvd

+0

@ hvd是的,看起來像那樣。但是我發現我過度使用了代碼;沒有必要使用RTTI(不知道D2006,但2010年工作正常)。我已經更新了答案; – teran