构造函数和inheritance

让我们在C#中举个例子

public class Foo { public Foo() { } public Foo(int j) { } } public class Bar : Foo { } 

现在,除了构造函数之外,Foo的所有公共成员都可以在Bar中访问。 我做不了类似的事情

 Bar bb = new Bar(1); 

为什么构造函数不可inheritance?

UPDATE

我知道我们可以链接构造函数,但我想知道为什么上面的构造无效。 我相信它应该是有正当理由的。

构造函数不可inheritance,因为它可能会导致奇怪和无意的行为。 更具体地说,如果向基类添加了新的构造函数,则所有派生类都将获取该构造函数的实例。 在某些情况下这是一件坏事,因为您的基类可能指定了对派生类没有意义的参数。

一个常见的例子是,在许多语言中,所有对象的基类(通常称为“对象”)都有一个没有参数的构造函数。 如果inheritance构造函数,这意味着所有对象都有一个无参数构造函数,并且没有办法说“我希望制作此类实例的人提供参数X,Y和Z,否则他们的代码不应该编译。 “ 对于许多类,重要的是为其正确的函数定义某些参数,并使构造函数不可遗传是类作者可以保证始终定义某些参数的方式的一部分。

编辑以响应注释:Ramesh指出,如果构造函数是按照他们希望的那样inheritance的,那么他总是可以在每个派生类中使用私有声明的构造函数来覆盖基类构造函数。 这当然是正确的,但这个策略存在后勤问题。 它要求派生类的编写者必须密切关注基类,并且如果他们想要基类构造函数的块inheritance,则添加私有构造函数。 对于编写派生类的人来说,这不仅是很多工作,这种跨类的隐式依赖正是导致奇怪行为的那种东西。

Ramesh – 并不是你所描述的不可能添加到语言中。 一般情况下,它没有完成,因为这种行为可能会让人感到困惑并导致大量的额外调试和代码编写。

Quintin Robinson在评论中提供了一些非常有价值的回答,这些评论绝对值得一读。

它们是(通过链接),你必须在派生对象中链接构造函数.IE:

 public class Foo { public Foo() { } public Foo(int j) { } } public class Bar : Foo { public Bar() : base() { } public Bar(int j) : base(j) { } } 

然后,派生对象中的构造函数将链接调用基础对象中的构造函数。

如果您想进一步阅读, 本文将提供更多示例。

您可能将构造函数引入类的一个原因是因为没有特定的“依赖项”而拥有该类的实例是没有意义的。 例如,它可能是必须与数据库连接的数据访问类:

 public class FooRepository { public FooRepository(IDbConnection connection) { ... } } 

如果基类中的所有公共构造函数都可用,那么存储库类的用户将能够使用System.Object的默认构造函数来创建类的无效实例:

 var badRepository = new FooRepository(); 

默认情况下隐藏inheritance的构造函数意味着您可以强制执行依赖项而不必担心用户创建“无效”实例。

假设构造函数是可inheritance的。 如果对子类没有意义,在许多情况下如何禁用inheritance的构造函数?

语言设计者选择简单地使构造函数不可inheritance,而不是使用阻止inheritance的机制使语言复杂化。

Foo构造函数只能知道如何初始化Foo对象,所以它也应该知道如何初始化任何潜在的子类是没有意义的

 public class Bar : Foo { public Bar(int i) : base(i) { } } 

构造函数讲述的故事是:“嘿基类请做你需要做的任何工作才能处于良好的状态,以便我可以继续正确地进行自我设置”。

由于设计原因,构造函数不可inheritance。 (请注意,这与我所知道的每种面向对象语言中的情况相同。)简单的答案是,在许多情况下,您真的不希望与基类相同的构造函数可用。 有关更完整的解释,请参阅此SO线程 。

一些讨论

  • 乔尔的论坛
  • Eric Gunnerson的博客

基本思想是尽可能多地为创作者提供控制。 你可以拥有私人基地。 你是如何创建对象的呢?

我想你可以做到以下几点:

 public class Bar : Foo { public Bar (int i) : base (i) { } } 

我可能有点偏离 – 但这是一般的想法。

简单的答案是语言不能以这种方式工作。

你要问的真正问题是为什么它不能那样工作:-)嗯,这是一个随意的选择,它继续来自C ++和Java(很可能还有很多其他影响C#的语言)。

可能的原因是编译器只会生成一个不带参数的构造函数,而只是调用父元素,如果你想要的更多,那么编译器会让你自己做。 这是最好的选择,因为你做的不仅仅是调用父构造函数。

真的,因为父构造函数不会完全初始化子对象。 在这方面,构造函数是一种个人的东西。 这就是大多数语言不inheritance构造函数的原因。