【问题标题】:Why child class variable initialize before parent class member variable为什么子类变量在父类成员变量之前初始化
【发布时间】:2013-12-31 01:26:12
【问题描述】:

考虑下面的代码。 ij 字段在 mn 之前初始化。我们知道父对象是在子对象之前创建的,但是在我的程序中,编译器在基类之前为子类的成员变量分配和初始化内存。这是为什么呢?

class X
{
    private int m = 0;
    private int n = 90;
    public X() { }
}

class Y:X
{
    private int i = 8;
    private int j = 6;
    public Y()
    { }
    public static void Main(string []args)
    {
        Y y1 = new Y();  
    }
}

【问题讨论】:

  • 不清楚你的问题是什么。
  • i 和 j 在 m 和 n 之前初始化,我们知道父对象先创建,然后再创建子对象。但是在我的程序编译器中,在基类之前为子类成员变量分配和初始化内存
  • “我们知道父对象是在子对象之前创建的”不是必须的真实陈述。 Y 是具有 4 个字段的单个对象 - 因此所有 4 个字段的空间将同时分配。 BartoszKP 的 +1 答案中的链接介绍了初始化顺序。

标签: c# inheritance constructor initialization


【解决方案1】:

这在Eric Lippert's blog中有解释:

[...] 一个已初始化的只读字段始终在其初始化状态下被观察到,除非我们先运行所有初始化程序,然后运行所有构造函数体,否则我们无法保证。

不知道为什么在这里提到readonly,但是例如,这可以确保以下场景虽然很愚蠢,但可以正常工作:

1.

class Base
{
    public Base()
    {
        if (this is Derived) (this as Derived).Go();
    }
}

class Derived : Base
{
    X x = new X();

    public void Go()
    {
        x.DoSomething(); // !
    }
}

2.

class Base
{
    public Base()
    {
        Go();
    }

    public virtual Go() {}
}

class Derived : Base
{
    X x = new X();

    public override void Go()
    {
        x.DoSomething(); // !
    }
}

此顺序在C# Language Specification (17.10.2) 中明确说明:

[...] 构造函数隐式执行由其类中声明的实例字段的变量初始化器指定的初始化。这对应于在进入构造函数时和隐式调用直接基类构造函数之前立即执行的一系列赋值。

【讨论】:

    【解决方案2】:

    这是对过程方法的理解使面向对象的方法更容易理解的少数几个地方之一。即使您使用的是 OOP,编译器仍然遵循程序逻辑 - 从头到尾工作。

    一个简单的例子是编译器命中private int n = 90。首先它为一个整数值分配空间,然后是一个标识符以将其作为整数访问,然后为其分配值 90。它无法分配该值,直到它都有空间粘贴它并且知道如何访问它,也不能访问不存在的空间。

    在这种情况下,您的派生类Y 构建在基类X 之上,类似于上面示例中变量n 构建在“类”integer 之上的方式。这是由声明 class Y:X 触发的 - 编译器在了解如何构建 X 之前甚至无法开始构建 Y

    【讨论】:

      【解决方案3】:

      必须允许子构造代码调用父级上的函数,除非父级已经完全构造,否则无法工作。

      但是,对象共享相同的内存块。所以所有的内存都是一次性分配的,然后根据类层次结构初始化类。

      【讨论】:

      • 但是OP说子字段在父字段之前初始化
      • @JuliánUrbano 我们正在描述不同的关系。类之间以及对象之间存在父/子关系。
      • 我不明白你的意思。您是说必须完全构造父级才能让子级调用它的函数,这意味着应该首先初始化父级,对吗? OP 说首先初始化的是孩子。
      猜你喜欢
      • 2021-08-31
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-11-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多