2010-09-19 58 views
41

我有一個基類和一個類繼承基地。基類有幾個虛擬函數,繼承類可能會覆蓋。但是,基類中的虛函數具有必須在繼承類覆蓋被調用之前運行的代碼。有什麼方法可以先調用基類虛函數,然後繼承類重寫。不需要調用base.function()。呼叫基地功能,然後繼承函數

我知道我可以簡單地做兩個函數,一個被調用,另一個虛擬。但是有沒有辦法讓我保持同樣的名字?我知道我可能需要改變一些事情。

class myBase 
{ 
    public virtual myFunction() 
     { /* must-run code, Called first */ } 
} 

class myInherited : myBase 
{ 
    public override myFunction() 
     { /* don't use base.myFunction();, 
     called from base.myFunction(); */ } 
} 

同類問題here

回答

44

可以在.NET Framework中找到的常見解決方案是在公用方法XXX中分割方法,並使用公用方法調用的受保護的虛擬方法OnXXX。對於你的榜樣,它應該是這樣的:

class MyBase 
{ 
    public void MyMethod() 
    { 
     // do something 
     OnMyMethod(); 
     // do something 
    } 

    protected virtual void OnMyMethod() 
    { 
    } 
} 

class MyInherited : MyBase 
{ 
    protected override void OnMyMethod() 
    { 
     // do something 
    } 
} 
+0

有沒有一種方法可以做到這一點,而無需在基類中創建兩個函數?或者至少讓他們有相同的名字? – Dave 2010-09-19 22:23:46

+3

@Dave:不,在虛擬方法調用之前或之後,無法神奇地調用重寫的基本方法。你必須以某種方式分割它。 (如果將它分開,除了在受保護的方法之前和之後執行某些操作外,還可以強制重寫方法調用重寫的基本方法。) – dtb 2010-09-19 22:25:31

+3

這也稱爲非虛擬接口習慣用法 - http:// en。 wikibooks.org/wiki/More_C%2B%2B_Idioms/Non-Virtual_Interface – sll 2011-10-12 15:07:42

60

C#沒有用於自動執行這種支持,但 您可以通過使用template method pattern強制執行。例如,假設你有這樣的代碼:

abstract class Animal 
{ 
    public virtual void Speak() 
    { 
     Console.WriteLine("I'm an animal."); 
    } 
} 

class Dog : Animal 
{ 
    public override void Speak() 
    { 
     base.Speak(); 
     Console.WriteLine("I'm a dog."); 
    } 
} 

這裏的問題是,任何類從Animal需要繼承調用base.Speak();確保執行基本行爲。您可以通過以下(略有不同)的方式自動執行此:

abstract class Animal 
{ 
    public void Speak() 
    { 
     Console.WriteLine("I'm an animal."); 
     DoSpeak(); 
    } 

    protected abstract void DoSpeak(); 
} 

class Dog : Animal 
{ 
    protected override void DoSpeak() 
    { 
     Console.WriteLine("I'm a dog."); 
    } 
} 

在這種情況下,客戶端仍然只能看到多態性Speak方法,但Animal.Speak行爲是保證執行。問題是,如果你有進一步的繼承(例如class Dachshund : Dog),你必須創建另一個抽象方法,如果你想Dog.Speak被保證執行。

0

除了你已經命名的兩種方法之外,沒有辦法做你正在尋找的東西。

您可以在基類中創建2個函數,一個被調用,另一個虛擬。

或者您在子類中調用base.functionName。

0

不完全。但我使用抽象方法做了類似的事情。

抽象方法必須被派生類重寫。抽象過程是虛擬的,所以你可以確定當基類調用它們時,調用派生類的版本。然後讓你的基類的「必須運行代碼」在運行後調用抽象過程。瞧,你的基類的代碼總是先運行(確保基類過程不再是虛擬的),然後是派生類的代碼。

class myBase 
{ 
    public /* virtual */ myFunction() // remove virtual as we always want base class's function called here 
    { /* must-run code, Called first */ 

     // call derived object's code 
     myDerivedMustcallFunction();  
    } 

    public abstract myDerivedMustCallFunction() { /* abstract functions are blank */ } 
} 

class myInherited : myBase 
{ 
    public override myDerivedMustCallFunction() 
    { /* code to be run in derived class here */ } 
} 
+1

爲什麼抽象方法是公開的? – Casey 2014-04-03 19:01:09

0

您怎麼看待這個問題?

class myBase 
{ 
    public void myFunctionWrapper() 
    { 
     // do stuff that must happen first 
     // then call overridden function 
     this.myFunction(); 
    } 

    public virtual void myFunction(){ 
     // default implementation that can be overriden 

    } 

} 

class myInherited : myBase 
{ 
    public override void myFunction() 
    { 

    } 
}