C#继承和默认构造函数

53
假设有一个基类 A 和一个从 A 派生的类 B。我们知道,类 B 不会继承类 A 的构造函数。然而,当创建 B 类的新对象时,会在调用 B 类的默认/自定义构造函数之前调用 A 类的默认构造函数。可能这样做的目的是需要将类 A 的字段初始化为默认值。
现在,假设类 A 定义了一个自定义构造函数。这意味着编译器会自动移除类 A 的默认构造函数。在创建类 B 的新实例时,哪个构造函数会在调用类 B 的构造函数之前被自动调用?(在这种情况下,类 A 的字段如何被初始化?)

3
我没有意识到OOPS指的是面向对象编程(Object Oriented Programming)中的S*。我不建议修改原文,因为我喜欢将它看作"oops" - Sam Berry
已经撤销了删除C#标签的编辑,并且为了更清晰而编辑了主题行。这绝对是一个特定于语言的问题。 - Jon Skeet
4个回答

64

现在,当创建类B的一个新实例时,在调用类B的构造函数之前,哪个类A的构造函数会自动调用?

基本上,代码将无法编译。每个构造函数必须链接到另一个构造函数,可以隐式或显式地链接到同一类中的构造函数(使用this)或基类中的构造函数(使用base)。

像这样的构造函数:

public B() {}

是隐含的:

public B() : base() {}

如果您根本未指定构造函数,它将以相同的方式隐式添加 - 但仍然必须有某些内容可供调用。因此,例如,您的情况:

public class A
{
    public A(int x) {}
}

public class B : A {}

会导致编译器错误:

错误 CS7036:没有提供与"A.A(int)"的必需形式参数'x'相对应的参数

但是,您可以显式指定不同的构造函数调用,例如:

public B() : base(10) {} // Chain to base class constructor
或者
public B() : this(10) {} // Chain to same class constructor, assuming one exists

在类A中指定一个显式的空构造函数会消除错误吗? - helloworld
2
@helloworld:一个没有参数的构造函数?当然可以。你所链接的构造函数不必由编译器隐式引入 - 它可以是普通的无参构造函数,也可以是只有可选参数或只有 params 参数的构造函数。基本上,只要 : base() 能够工作,就可以了。 - Jon Skeet

6
一旦您为class A提供自己的构造函数,在class B对象创建期间不会发生自动调用。在class B构造函数的第一行应该是super(paramsToClassAConstructor),或者可以使用this()调用class B中的另一个构造函数。在这种情况下,class B中的第二个构造函数负责调用class A构造函数。

你所写的适用于Java,但问题的标签是C#,其规则不同。 - bstenzel
1
哦,我的天啊...我没有看标签...谢谢你让我开了眼界 :) - Bhargav Kumar R

4
当构造函数完成执行时,对象处于有效的初始状态。我们应该使用有效的对象。
当为类A提供非默认构造函数时,实际上是在说——构造类A对象,即使其处于有效的初始状态——我们需要更多的信息,这些信息由参数提供。
鉴于此,编译器通过不生成默认构造函数来帮助(因为我们怎样才能让对象处于有效状态?),客户端代码将无法编译,客户端程序员必须注意到这一点。
当您提供显式的空构造函数时,您实际上是在告诉编译器——我知道我在做什么——默认构造函数可能会将字段初始化为某些合理的默认值。或者为了促进重用,可以使用默认构造函数调用带有一些默认值的非默认构造函数。
子类知道其超类——子类构造函数可以调用超类方法(一些常用的重用方法在子类中)。基于上述原因,要求超类部分应处于有效状态,即在任何方法调用之前都应先执行其构造函数。这就需要在子类构造函数之前调用超类构造函数。
基于这些,您将能够轻松地设计构造函数以强制正确的初始状态行为。

1

定义基类参数构造函数没有特殊的规则。规则与其他类构造函数相同。您可以按照以下方式定义多个构造函数:

class baseclass
    {
        public baseclass()
        {

        }
        public baseclass(string message)
        {

        }
    }

如果基类有构造函数,则子类或派生类需要从其基类调用构造函数。
class childclass : baseclass
    {
        public childclass()
        {
        }
        public childclass(string message)
            : base(message)
        {            
        }
    }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接