2012-02-23 76 views
7

我以爲我有這個釘子,然後我去看看工作中的某些源,並且想知道爲什麼我從msdn讀取的內容和我在源代碼中看到的內容中存在如此多的矛盾。 ...C#虛擬&覆蓋關鍵字

我的理解是,虛擬關鍵字可以在方法聲明中使用,以允許任何派生類來覆蓋它。然後

override關鍵字將需要在執行超類的虛擬方法,當派生的類中使用....

例如:

public abstract class A 
{ 
    public virtual string GetName(); 
} 


public class B:A 
{ 

    //assume there are some defined properties. 
    public override string GetName() 
    { 
     return FirstName; 
    } 
} 

我有幾個問題:

1)如果沒有實現方法,是否真的需要定義一個虛擬方法?當然它可以被覆蓋在子類中而不使用虛擬和覆蓋?

2)如果(1)不正確,我是正確的思維,每一個虛擬方法必須在子類中使用它來覆蓋....

編輯:

你說得對我的代碼不會編譯......我想知道爲什麼....我uinderstand你的答案,但後來我看到了這一點:

public abstract class RequestHandler<TRequest, TResponse> : RequestHandler, IRequestHandler<TRequest>, IRequestHandler, IDisposable, ITypedRequestHandler 
    where TRequest : global::Agatha.Common.Request 
    where TResponse : global::Agatha.Common.Response, new() 
{ 
    protected RequestHandler(); 

    public virtual void AfterHandle(TRequest request); 
    public virtual void BeforeHandle(TRequest request); 
    public override Response CreateDefaultResponse(); 
    public TResponse CreateTypedResponse(); 
    public override Response Handle(Request request); 
    public abstract Response Handle(TRequest request); 
} 

以上不導致編譯器抱怨......

+0

您的示例沒有編譯(「'A.GetName()」必須聲明一個主體,因爲它沒有被標記爲'abstract','extern'或'partial'「)。 – dtb 2012-02-23 11:08:51

+0

您的A級人員會編寫它缺少的摘要嗎? – V4Vendetta 2012-02-23 11:09:48

+0

當然A類中的方法應該是public abstract string GetName(); – Vedran 2012-02-23 11:11:33

回答

10

第一屆上面的代碼無效。虛擬方法仍然必須具有默認實現的主體。要做你以上所做的事情,你需要使用abstract keyaord而不是虛擬的。

abstract意味着沒有提供方法體,但是從它派生的任何類必須實現此方法(除非它也是抽象的)。

我認爲這幾乎回答您的問題....

  1. 如果它沒有實現,那麼它不能是虛擬的,它必須是抽象的。如果它有一個什麼都不做的實現,那麼必須實現。

  2. 虛擬課堂的關鍵在於它具有默認行爲,因此您可以選擇是否覆蓋它。如果它是抽象的,那麼你將不得不重寫它(除非你是派生另一個抽象類)。

+0

是的,這正是我的想法,但我在這裏有一些來源,不會導致編譯器抱怨...請參閱上面的編輯 – user559142 2012-02-23 11:11:43

+0

正是。如果實際存在,使用'virtual'就不會在繼承類中實現該方法。 – Aphelion 2012-02-23 11:12:18

+0

謝謝,這是有道理的,但我仍然在編輯 – user559142 2012-02-23 11:22:06

0

OK,通過聲明方法爲虛擬(和不希望重寫子類中的方法),你會如果你介紹用同樣的方法輸入法隱藏的世界名稱到子類中。你必須爲這樣定義它:

public abstract class A 
{ 
    public virtual string GetName() 
    { 
     return null; 
    } 
} 

public class B : A 
{ 
    //assume there are some defined properties. 
    public new string GetName() 
    { 
     return FirstName; 
    } 
} 

我建議你認爲抽象的覆蓋方式:

public abstract class A 
{ 
    public abstract string GetName() 
} 

// to override 
public class B : A 
{ 
    //assume there are some defined properties. 
    public override string GetName() 
    { 
     return FirstName; 
    } 
} 

這將是完全不同的。我強烈建議你重寫子類中的抽象方法。

然而,這裏對這個問題的一個快速REF(舊的,但一個良好的閱讀):

http://www.akadia.com/services/dotnet_polymorphism.html

+0

上面的來源困惑這不會編譯,你不能隱藏一個抽象的方法。 – softveda 2012-02-23 11:14:37

+0

ahh -ok,在這種情況下,A類必須是虛擬的。將修改回答 – 2012-02-23 11:19:32

+0

你其實**不能**避免重寫抽象方法。這是強制性的。 – Tigran 2012-02-23 11:20:07

2

真的有必要定義一個方法,虛擬若沒有執行?

您可以使抽象方法(它會隱式地使其變爲虛擬)。

當然,它可以在沒有使用虛擬和覆蓋的子類中被覆蓋?

如果你只是「覆蓋」它沒有明確地覆蓋它,它不會是同樣的方法,並呼籲基類的變量的方法不會叫派生法(它不會參與多態)。你只需要「隱藏」基類的方法(編譯器實際上就此提醒你,如果它確實是你想做的事情,你必須使用new修飾符。)

一個例子會使它更加清晰:

class B 
{ 
    public virtual void M() { Console.WriteLine("B.M") }; 
} 

class D1 : Base 
{ 
    // Hides the base method 
    public new void M() { Console.WriteLine("D1.M") }; 
} 


class D2 : Base 
{ 
    // Overrides the base method 
    public override void M() { Console.WriteLine("D2.M") }; 
} 

... 

D1 d1 = new D1(); 
d1.M(); // Prints "D1.M" 
B b1 = d1; 
b1.M(); // Prints "B.M", because D1.M doesn't override B.M 

D2 d2 = new D1(); 
d2.M(); // Prints "D2.M" 
B b2 = d2; 
b2.M(); // Also prints "D2.M", because D2.M overrides B.M 

如果(1)不正確,我是正確的思維,每一個虛擬方法必須在使用它的子類中重寫....

沒有,只有當它的抽象.. 。一個虛擬方法可以有一個實現,並且在那案例派生類不會被強制覆蓋它。

0

需要virtual是由多態性決定的。想想看,當你使用new重新定義子類中的方法會發生什麼:

class Parent 
{ 
    void Foo() { Console.WriteLine("Parent"); } 
    virtual void Bar { Console.WriteLine("Parent"); } 
} 

class Child : Parent 
{ 
    new void Foo() { Console.WriteLine("Child"); } // another method Foo 
    override void Bar { Console.WriteLine("Child"); } 
} 

var child = new Child(); // a Child instance 
var parent = (Parent)child; // same object, but statically typed as Parent 

c.Bar(); // prints "Child" 
p.Bar(); // again, prints "Child" -- expected virtual behavior 

c.Foo(); // prints "Child" 
p.Foo(); // but this prints "Parent"!! 

出於這個原因,那些打算從派生類(即不sealed)應始終標記可以被覆蓋爲virtual方法否則會出現像上面那樣混亂的運行時行爲。如果父實現實際上做了任何事情都沒有區別;關鍵是它行爲不同

0

這正是一個virtualabstract方法之間的區別:

虛擬方法可以通過派生類中重寫如果選擇。虛擬方法可能有也可能沒有默認的繼承者調用的實現,這是通過base關鍵字完成的。

摘要方法必須被派生類覆蓋。其約束條件如下:

  • 它只能在抽象類中定義。
  • 它不能有一個實現,因爲它要由繼承者來定義它的行爲。
0

1)是否真的有必要定義一個方法,虛擬若沒有 實施?當然,它可以在子類 中被覆蓋而不使用虛擬和覆蓋?

如果從類中,你必須重寫該方法得到您可以使用abstract方法,有沒有身體,但他們。 所有抽象方法都必須在子類中重寫。

2)如果(1)不正確,我是正確的思維,每一個虛擬 方法必須在子類中使用它來覆蓋....

不,相反,你可以使用virtual關鍵字在裏面有一個實現,但是做而不是在子類中強制重寫。從這個角度來看,給你更多的靈活性。

Usauly他們使用abstract爲孩子的創造剛性約束,所以孩子從中獲得的必須實現基類的指定成員。

1

1)是否真的有必要定義一個方法,虛擬若沒有執行?當然它可以被覆蓋在子類中而不使用虛擬和覆蓋?

正如在其他答案中所述,virtual方法需要實現。你用abstract混淆了它。

如果你問virtual方法,其是否有實施需要申報virtual:在C#中,是的,這是必要的。在Java中,您可以覆蓋任何舊的方法。這是一個C#設計決定,要求覆蓋被關鍵字virtual明確允許,以便方法不能被覆蓋,除非程序員有意。

如果程序員由於沒有使用virtual而沒有表達意圖,您仍然可以使用new關鍵字「覆蓋」方法。但是,這有點不同。希望這個代碼將有助於說明這一概念:

class Program 
{ 
    static void Main(string[] args) 
    { 
     var baseC = new BaseClass(); 
     var extC = new ExtClass(); 
     var lazyC = new LazyClass(); 

     Console.WriteLine(baseC.NewMethod()); 
     Console.WriteLine(baseC.VirtualOverrideMethod()); 

     Console.WriteLine("---"); 

     Console.WriteLine(extC.NewMethod()); 
     Console.WriteLine(extC.VirtualOverrideMethod()); 

     Console.WriteLine("---"); 

     Console.WriteLine(((BaseClass) extC).NewMethod()); 
     Console.WriteLine(((BaseClass) extC).VirtualOverrideMethod()); // Redundant typecast 

     Console.WriteLine("---"); 

     Console.WriteLine(lazyC.VirtualOverrideMethod()); 

     Console.ReadKey(); 
    } 

    public class BaseClass 
    { 
     public BaseClass() 
     { 

     } 

     public string NewMethod() 
     { 
      return "NewMethod of BaseClass"; 
     } 

     public virtual string VirtualOverrideMethod() 
     { 
      return "VirtualOverrideMethod of BaseClass"; 
     } 
    } 

    class ExtClass : BaseClass 
    { 
     public new string NewMethod() 
     { 
      return "NewMethod of ExtClass"; 
     } 

     public override string VirtualOverrideMethod() 
     { 
      return "VirtualOverrideMethod of ExtClass"; 
     } 
    } 

    class LazyClass : BaseClass 
    { 
    } 
} 

輸出:

NewMethod of BaseClass 
VirtualOverrideMethod of BaseClass 
--- 
NewMethod of ExtClass 
VirtualOverrideMethod of ExtClass 
--- 
NewMethod of BaseClass 
VirtualOverrideMethod of ExtClass 
--- 
VirtualOverrideMethod of BaseClass 

2)如果(1)不正確,我是正確的思維,每一個虛擬方法,必須在被覆蓋子類使用它....

沒有。 virtual是一種說法,「如果您想重寫此方法,那沒關係」。事實上,我在上面的代碼中包含LazyClass來顯示。

以上不導致編譯器抱怨......

我還沒有使用的接口不多,但看起來像一個。在我的代碼,如果我改變

class ExtClass : BaseClass 
    { 
     public new string NewMethod() 
     { 
      return "NewMethod of ExtClass"; 
     } 

     public override string VirtualOverrideMethod() 
     { 
      return "VirtualOverrideMethod of ExtClass"; 
     } 
    } 

到:

class ExtClass : BaseClass 
    { 
     public new string NewMethod() 
     { 
      return "NewMethod of ExtClass"; 
     } 

     public override string VirtualOverrideMethod() 
     { 
      return "VirtualOverrideMethod of ExtClass"; 
     } 
    } 

我得到:

error CS0501: 'OverrideTest.Program.ExtClass.VirtualOverrideMethod()' must declare a body because it is not marked abstract, extern, or partial 

從Visual Studio 2010中同樣爲我BaseClassvirtual方法。