假设有一个基类A
和一个来自B
的类A
。
然后,我们知道类A
的构造函数永远不会被类B
继承。但是,当创建B
的新对象时,则会调用类A
的默认构造函数,然后调用类B
的默认/自定义构造函数。也许这样做的目的是需要将类A
的字段初始化为默认值。
现在,假设类A
已定义了自定义构造函数。这意味着编译器会以静默方式删除类A
的默认构造函数。现在,在创建类B
的新实例时,在调用类A
的构造函数之前会自动调用类B
的构造函数? (在这种情况下,如何初始化类A
字段?)
答案 0 :(得分:57)
现在,在创建类
B
的新实例时,在调用类A
构造函数之前会自动调用哪个类B
的构造函数?
代码基本上无法编译。每个构造函数都必须隐式或显式地链接到另一个构造函数。它链接到的构造函数可以在同一个类(带有this
)或基类(带base
)。
像这样的构造函数:
public B() {}
隐含地:
public B() : base() {}
...如果你根本没有指定构造函数,它将以相同的方式隐式添加 - 但它仍然需要调用。例如,您的方案:
public class A
{
public A(int x) {}
}
public class B : A {}
导致编译器错误:
错误CS7036:没有给出与
'x'
所需的形式参数'A.A(int)'
对应的参数
但是,您可以明确指定不同的构造函数调用,例如
public B() : base(10) {} // Chain to base class constructor
或
public B() : this(10) {} // Chain to same class constructor, assuming one exists
答案 1 :(得分:6)
在class A
提供自己的构造函数后,class B
对象创建期间不会发生自动调用。
class B
构造函数中的第一行应为super(paramsToClassAConstructor)
,或者可以使用class B
调用this()
中的其他构造函数。 class B
中的第二个构造函数负责在这种情况下调用class A
构造函数。
答案 2 :(得分:3)
当构造函数完成执行时 - 对象处于有效的初始状态。我们应该使用有效的对象。
当我们为A类提供非默认构造函数时 - 我们实际上是在说 - 构造A类对象,即处于有效的初始状态 - 我们需要更多的信息 - 由参数提供。
鉴于此,编译器通过而不是生成默认构造函数。客户端代码将无法编译(因为它应该 - 我们将如何使对象落在有效状态?) - 客户端程序员必须坐下来注意。
当你提供一个显式的空构造函数 - 你实际上在告诉编译器 - 我知道我在做什么 - 默认构造函数很可能会将字段初始化为一些合理的默认值。
或者为了促进重用 - 默认构造函数可以使用一些默认值来调用非默认值
子类知道它的超类 - 子类构造函数可以调用超类方法 - (子类中一些常用的重用方法)。鉴于上述情况 - 这要求超类部分应处于有效状态 - 即其构造函数在其任何方法调用之前执行。这需要在子类构造函数之前调用超级构造函数
鉴于此 - 您可以轻松地设计构造函数以强制执行正确的初始状态行为。
答案 3 :(得分:0)
定义基类参数构造函数没有特殊的规则。规则与其他类构造函数相同。您可以定义构造函数的数量,如下所示:
class baseclass
{
public baseclass()
{
}
public baseclass(string message)
{
}
}
如果基类具有构造函数,则需要子类或派生类从其基类调用构造函数。
class childclass : baseclass
{
public childclass()
{
}
public childclass(string message)
: base(message)
{
}
}