2010-02-19 109 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