构造函数和继承

时间:2009-03-06 00:44:27

标签: c# oop inheritance

让我们以C#

为例
public class Foo
{
    public Foo() { }
    public Foo(int j) { }
}

public class Bar : Foo
{

}

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

这样的事情
Bar bb = new Bar(1);

为什么构造函数不可继承?

更新

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

10 个答案:

答案 0 :(得分:16)

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

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

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

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

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

答案 1 :(得分:8)

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

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

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

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

如果您想进一步阅读,

This article会提供更多示例。

答案 2 :(得分:2)

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

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

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

var badRepository = new FooRepository();

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

答案 3 :(得分:2)

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

是没有意义的。
public class Bar : Foo
{
public Bar(int i) : base(i) { }
}

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

答案 4 :(得分:2)

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

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

答案 5 :(得分:1)

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

答案 6 :(得分:1)

一些讨论

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

答案 7 :(得分:0)

我认为你可以做到以下几点:

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

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

答案 8 :(得分:0)

简单的答案是语言不起作用。

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

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

答案 9 :(得分:0)

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