2008-12-24 82 views
19

我正在看堆棧溢出問題What is the difference between abstract function and virtual function?,我想知道每個抽象函數是否應該被認爲是C#中的虛函數還是一般?在C#中,每個抽象函數都是虛擬的嗎?

我對「你必須重寫/你可能會忽略」對這個問題的回答有些困惑。不是C#程序員,我傾向於認爲抽象函數只是一個編譯時概念,而抽象函數是定義的虛函數,因爲您必須至少提供一個,但可以在層次結構的更下方提供多個實現。

虛擬函數也具有編譯時間維度,因爲您不能覆蓋非虛函數,但它們大多是運行時概念,因爲它只是基於實際的接收器選擇了正確的方法實現。

回答

45

是的。從C# 3.0 spec的部分10.6.6:

當一個實例方法聲明 包括一個抽象的改性劑,該方法 被說成是一個抽象方法 。雖然抽象方法隱含地也是虛擬方法,但其 不能具有虛擬修飾符。

+2

你不能得到比拉出C#規範更好的答案。 :) – Quibblesome 2008-12-24 15:28:23

2

是的。爲證明:

abstract class A { 
    public abstract void Foo(); 
} 
class B : A { 
    public override void Foo() 
    { /* must do */ } 
} 
class C : B { 
    public override void Foo() 
    { /* can do */ } 
} 
1

是的。

抽象屬性聲明指定屬性的訪問是虛擬的,但不提供實際實現的訪問器。 (MSDN

0

我想你是從「C++」的角度來看問題(簡潔,避免必要的關鍵字,保存擊鍵)。

C#哲學是代碼的意圖應該從閱讀源碼中明確,編譯器應該能夠儘可能地驗證這個意圖。因此,雖然抽象方法和虛擬方法(或者抽象方法和非抽象類之間;或者out參數和ref參數之間)之間生成的MSIL幾乎沒有什麼不同, ,額外的關鍵字會告訴維護程序員一些東西,並讓編譯器仔細檢查你在做什麼。

3

是虛擬(和喬恩斯基特已經掀起了規範,以證明它),因爲,給抽象基類的引用,具體的派生類的實現必須調用。例如,給定的經典動物層次:

abstract class Animal{ 
    public abstract void Speak(); 
} 

class Cat : Animal{ 
    public override void Speak(){Console.WriteLine("meow");} 
} 

class Dog : Animal{ 
    public override void Speak(){Console.WriteLine("bark");} 
} 

接受一個Animal對象,並調用其Speak方法就不知道該調用哪個執行,如果函數不是虛函數。

static void TalkToAnimal(Animal a){ 
    Console.WriteLine("Hello, animal."); 
    a.Speak(); 
} 

不過請注意,該接口實現是默認情況下虛擬的。由於接口與類的工作方式不同,真正的多態性對於查找接口方法的實現沒有必要。

+0

抽象方法不需要是虛擬的,它們可以提供另一個關鍵字,它只是在具體類中實現它,但不允許子類進一步覆蓋它。 – 2009-07-02 09:46:56