2010-02-19 99 views
39

可能重複:
Why can’t I create an abstract constructor on an abstract C# class?抽象構造函數在C#

爲什麼我不能宣佈我的類的抽象的構造是這樣的:

public abstract class MyClass { 
    public abstract MyClass(int param); 
} 
+3

看起來構造函數是一個實現細節,因此強制子類以某種方式構建將是一件壞事。如果你想要一個封裝結構,使用靜態工廠模式。 – 2010-02-19 19:52:47

+0

看起來他希望使用當前的通用結構子類型/參數構造函數不可能實現的功能。 – Dykam 2010-02-19 20:09:08

+0

你試圖完成什麼?也許還有另一種看待它的方式。 – fre0n 2010-02-19 20:21:57

回答

61

構造函數只適用於它們被定義的類,也就是說它們不是被繼承的。使用基類構造函數(您必須調用其中的一個,即使僅自動調用默認類),但不會通過派生類重寫。您可以在抽象基類上定義構造函數 - 它不能直接使用,但可以通過派生類來調用。你不能做的是強制派生類來實現特定的構造函數簽名。

爲了爲所有派生類定義一些常用的設置代碼,定義一個構造函數是非常合理的,典型情況下它是受保護的。當抽象類提供依賴於此設置的其他一些默認行爲時,情況尤其如此。例如:

public abstract class Foo 
{ 
    public string Name { get; private set; } 

    protected Foo(string name) 
    { 
     this.Name = name; 
    } 
} 

public class Bar : Foo 
{ 
    public Bar() : base("bar") 
    { 
     ... 
    } 
} 
+4

你沒有錯,但我會澄清一件事:構造函數不是繼承的,但它們*是*由孩子調用的。你唯一的選擇是*哪個*構造函數從你的鏈接。 – 2010-02-19 19:51:55

+0

我已更新並澄清。 – tvanfosson 2010-02-19 20:00:02

+0

@tvanfosson:_you可能意思是'酒吧'繼承'Foo'_ – comecme 2012-06-29 22:10:25

12

你可以用」 t聲明它abstract,但是你可以在你的抽象類上有一個構造函數;只要刪除單詞abstract併爲其提供一個機構。

+14

...併爲它提供一個機構。 – tvanfosson 2010-02-19 19:48:45

+4

將抽象類中的構造函數聲明爲** protected **也是一個好習慣。它強制這樣的事實,即類不能直接實例化。 – 2010-02-19 20:01:47

+0

@tvanfosson:謝謝你指出。當我讀到這個問題時我錯過了。 – 2010-02-19 21:10:17

0

根據定義,該類不能直接實例化,所以從某種意義上說,它已經是抽象的了。

+0

抽象方法直到由派生類提供時才具有主體。抽象類的構造函數絕對不是這樣。 – 2010-02-19 19:53:44

+0

我明白你的觀點。但是,這個問題的意圖更多地與繼承有關。 – 2010-02-19 19:55:02

3

因爲不支持抽象構造函數。

但是抽象類可以有一個構造函數。

3

什麼不對的:你迫使

public abstract class MyClass { 
    protected MyClass(int param) 
    { 
    } 
} 

在這種情況下,所有的派生類調用基類的構造函數。

+1

它強制類聲明一個構造函數,但不一定需要一個整數參數。你可以很容易地聲明它爲'public class NewClass:MyClass {public NewClass():base(0){}}' – tvanfosson 2010-02-19 19:47:59

+0

你可以在MyClass構造函數中使用參數驗證,並且由於參數無效而引發異常。但是你不能強制派生類將有效數據傳遞給MyClass構造函數,也不要在派生類中添加額外的構造函數。 – 2010-02-19 19:50:36

+1

小澄清 - 他們沒有*義務*稱它,但他們*可能*稱它。 – slugster 2010-02-19 19:54:29

6

摘要意味着虛擬。一個非默認構造函數永遠不會被多態調用,所以構造函數不允許虛擬和抽象。

如果在將來的C#版本中,泛型被增強以允許通過泛型類型參數調用非默認構造函數,那麼可能會對構造函數進行多態調用,並且可能還會添加虛擬和抽象構造函數。

+2

在泛型方法中調用非默認構造函數仍然不是多態調用,因爲該類型是事先已知的。構造函數永遠不能被稱爲多態的,句點。 – 2010-02-19 19:53:23

+0

@AntonTykhyy:在通用上下文*中調用*是多態的。 .NET泛型基於類型擦除和虛擬分派工作。它們並不像C++模板那樣專用於每種類型。 – 2016-12-29 15:35:53

+0

這就是如果你忽略價值類型。泛型關閉的價值類型是專門的。試想一下,有多糟糕的「List 」等等。但我明白你的意思。我想可以在'RuntimeTypeHandle'中爲通用約束中使用的每個構造函數添加一個插槽。但是如果稍後有人加載一個具有新的泛型構造函數約束的程序集呢?所有現有的'RuntimeTypeHandle'都必須更新。不是說它不能完成,只是很麻煩。 – 2017-03-14 12:12:02

5

構造函數更接近靜態方法而不是「常規」方法。與靜態方法類似,它們可以是重載,但不是重寫。也就是說,它們不是被繼承的,但可以被重新定義。

public BaseClass 
{ 
    public BaseClass(String s) { ... } 
    public static void doIt (String s) { ... } 
} 

public SubClass extends BaseClass 
{ 
    public SubClass(String s) { ... } 
    public static void doIt (String s) { ... } 
} 

public SubClass2 extends BaseClass 
{ 
} 

new SubClass("hello"); 
SubClass.doIt("hello"); 

new SubClass2("hello"); // NOK 
SubClass2.doIt("hello"); // NOK 

構造函數和靜態方法從未派出動態(幾乎) - 你總是知道你實例化的具體類型或具體類的靜態方法。這就是爲什麼抽象構造函數抽象靜態方法是沒有意義的。這就是爲什麼你也可以在接口中不指定構造函數和靜態方法。

你甚至可以認爲構造爲靜態工廠方法(看看corresponding pattern):

MyClass obj = new MyClass(); // the way it is 
    MyClass obj = MyClass.new(); // think of it like this 

我看到的唯一情況下它會是有意義的定義抽象構造函數或抽象靜態方法是如果使用反射。在這種情況下,你可以確保所有的子類都會重新定義相應的靜態方法或構造函數。但反射是另一個話題...

注意:在諸如Smalltalk等語言中,類是常規對象,您可以重寫靜態方法並具有抽象構造函數。但它並不適用於Java,因爲即使可以通過反射來獲取它們,類也不是「常規」對象。

+0

+1反射用例。 – fre0n 2010-02-19 20:24:06