2011-01-11 11 views
22

मैं एक आभासी विधि अधिभावी कर रहा हूँ, और मैं विरासत में मिला कॉल करना चाहते हैं। लेकिन मैं तत्काल पूर्वज कॉल करने के लिए नहीं करना चाहते, मैं से पहले एक कॉल करना चाहते हैं।डेल्फी: कैसे एक आभासी विधि पर विरासत में मिला विरासत में मिला पूर्वज कॉल करने के लिए?

TObject 
    TDatabaseObject 
     TADODatabaseObject <---call this guy 
     TCustomer  <---skip this guy 
      TVIP   <---from this guy 

मैं कास्टिंग की कोशिश की मेरी पूर्वज के रूप में self, और उस पर विधि कॉल, लेकिन यह पुनरावर्ती ढेर अतिप्रवाह को जन्म दिया:

procedure TVip.SetProperties(doc: IXMLDOMDocument); 
begin 
    TADODatabaseObject(Self).SetProperties(doc); //skip over TCustomer ancestor 
    ... 
end; 

मैं inherited कीवर्ड जोड़ने की कोशिश की, लेकिन वह ऐसा नहीं करता संकलन:

procedure TVip.SetProperties(doc: IXMLDOMDocument); 
begin 
    inherited TADODatabaseObject(Self).SetProperties(doc); //skip over TCustomer ancestor 
    ... 
end; 

संभव है?

+8

मैं @Ian लगता है अलार्म की घंटी अब आप के लिए बज किया जाना चाहिए! आपके सिस्टम के इस हिस्से का डिज़ाइन सही नहीं हो सकता है। –

+0

@ डेविड हेफ़र्नन और आप सही हैं। लेकिन पूर्वजों का नाटक 'TListView' है, मैं वास्तव में उस वर्ग को फिर से डिजाइन नहीं कर सकता जिसका मेरा कोई नियंत्रण नहीं है। –

+0

@ इयान किस बिंदु पर आपके पास नियंत्रण है? TADODatabaseObject? TCustomer? –

उत्तर

16

आप एक नियमित भाषा तरह से, के रूप में यह टूट जाएगा वस्तु उन्मुख नहीं कर सकते भाषा के पहलुओं।

आप पॉइंटर्स और चालाक के साथ चारों ओर झुका सकते हैं, लेकिन यह जवाब देने से पहले: क्या यह वास्तव में आप चाहते हैं?

दूसरों के रूप में उल्लेख किया है:। अपनी जरूरत के लिए एक गंभीर "डिजाइन गंध" (जो code smell के समान है, लेकिन और अधिक गंभीर है की तरह लगता है

संपादित करें:

सूचक सड़क तुम्हें बचा सकता है नगण्य नीचे जा रहे हैं अल्पावधि में काम करते हैं, और लंबे समय में आप काम के सप्ताह के खर्च
यह है कि इस पर कुछ अच्छा पढ़ने के लिए बनाता है:।। Upstream decisions, downstream costs

+1

+1 डिजाइन गंध –

+1

"ऐसा नहीं कर सकते" –

+2

यह ध्यान रखें कि आप एक अंतहीन प्रत्यावर्तन (ढेर अतिप्रवाह समय!) यदि आप "वर्ग पदानुक्रम कूद" करने की कोशिश प्राप्त कर सकते हैं दिलचस्प है और आप एक आभासी लागू कर रहे हैं के लिए स्वीकार किए जाते हैं के लिए तरीका। –

3

यदि आप वास्तव में ऐसा करना चाहते हैं तो आपको विरासत पदानुक्रम का एक अलग संरक्षित विधि में निकालना चाहिए जिसे आप सीधे संदर्भित करने में सक्षम होना चाहते हैं। यह आपको वर्चुअल विधि प्रेषण के बिना कहीं भी इसे कॉल करने की अनुमति देगा।

लेकिन, जैसा कि मैंने टिप्पणी की है, ऐसा लगता है आपकी वर्ग डिजाइन के साथ कुछ धराशायी हो है की तरह।

+0

दोनों के लिए: डिज़ाइन के साथ कुछ बंद है। लेकिन पूर्वज कैन्ड और कामकाजी है। मैं शायद प्रक्रिया में कई कीड़े पेश करने, इसे पूरी तरह से गले लगाने के अंत में खत्म हो जाएगा। मैं उम्मीद कर रहा था कि कोड की एक पंक्ति मुझे कुछ दिनों के काम बचाएगी। –

+0

मुझे एक ही समस्या थी। आधार वर्ग तीसरे पक्ष के घटक कोड की 30,000 लाइनें हैं। –

27

आप इसे स्थिर पता प्राप्त करने की एक हैक का उपयोग कर सकते आभासी विधि की:

type 
    TBase = class 
    procedure Foo; virtual; 
    end; 

    TAnsestor = class(TBase) 
    procedure Foo; override; 
    end; 

    TChild = class(TAnsestor) 
    procedure Foo; override; 
    procedure BaseFoo; 
    end; 

procedure TBase.Foo; 
begin 
    ShowMessage('TBase'); 
end; 

procedure TAnsestor.Foo; 
begin 
    ShowMessage('TAnsestor'); 
end; 

procedure TChild.Foo; 
begin 
    ShowMessage('TChild'); 
end; 

type 
    TFoo = procedure of object; 

procedure TChild.BaseFoo; 
var 
    Proc: TFoo; 

begin 
    TMethod(Proc).Code := @TBase.Foo; // Static address 
    TMethod(Proc).Data := Self; 
    Proc(); 
end; 

procedure TForm4.Button1Click(Sender: TObject); 
var 
    Obj: TChild; 
    Proc: TFoo; 

begin 
    Obj:= TChild.Create; 
    Obj.BaseFoo; 
// or else 
    TMethod(Proc).Code := @TBase.Foo; // Static address 
    TMethod(Proc).Data := Obj; 
    Proc(); 

    Obj.Free; 
end; 
+2

+1 यदि वह वास्तव में ऐसा करना चाहता है तो यह हो! –

+0

यह एक महान चाल है, मैंने इसे इस परिदृश्य में उपयोग किया - I एक तृतीय पक्ष ढांचे का उपयोग करें, विरासत विधि गलत चीज करता है - अपवादों को खाती है जिन्हें मैं पकड़ना चाहता हूं, इसलिए मुझे इसे छोड़ना होगा, इसके थोड़ा संशोधित तर्क को दोबारा लागू करना होगा, फिर "दादा" (टीबीएएस) की विधि को कॉल करें । –

7

मुझे याद है मैं कुछ साल पहले VCL पदानुक्रम के कुछ डिजाइन सीमा के आसपास काम कर कुछ इस तरह करना था।

तो ऐसा लगता है यह कुछ इस तरह था:

type 
    TGrandParent = class(TObject) 
    public 
    procedure Show;virtual; 
    end; 

    TParent = class(TGrandParent) 
    public 
    procedure Show;override; 
    end; 

    THackParent = class(TGrandParent) 
    private 
    procedure CallInheritedShow; 
    end; 

    TMyObject = class(TParent) 
    public 
    procedure Show;override; 
    end; 


{ TGrandParent } 

procedure TGrandParent.Show; 
begin 
    MessageDlg('I''m the grandparent', mtInformation, [mbOk], 0); 
end; 

{ TParent } 

procedure TParent.Show; 
begin 
    inherited; 
    MessageDlg('I''m the parent', mtInformation, [mbOk], 0); 
end; 

{ THackParent } 

procedure THackParent.CallInheritedShow; 
begin 
    inherited Show; 
end; 

{ TVIP } 

procedure TMyObject.Show; 
begin 
    THackParent(Self).CallInheritedShow; 
end; 

procedure TForm6.Button6Click(Sender: TObject); 
var 
    VIP: TMyObject; 
begin 
    VIP:=TMyObject.Create; 
    try 
    VIP.Show; 
    finally 
    VIP.Free; 
    end; 
end; 

खाने-सुंदर नहीं है लेकिन अभी भी एक समाधान :)

संबंधित मुद्दे