[英]Why child class variable initialize before parent class member variable
請考慮以下代碼。 字段i
和j
在m
和n
之前初始化。 我們知道父對象是在子對象之前創建的,但是在我的程序中,編譯器正在為基類之前的子類的成員變量分配和初始化內存。 這是為什么?
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();
}
}
Eric Lippert的博客解釋了這一點:
[...]初始化的只讀字段總是在其初始化狀態中被觀察到,除非我們首先運行所有初始化器,然后運行所有構造函數體,否則我們無法保證。
不確定為什么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#語言規范 (17.10.2)中明確說明:
[...]構造函數隱式執行由其類中聲明的實例字段的變量初始化程序指定的初始化。 這對應於在進入構造函數之后和直接調用直接基類構造函數之前立即執行的賦值序列。
必須允許子構造代碼調用父代的函數,除非父元素已經完全構造,否則它不能工作。
但是,對象共享相同的內存塊。 因此,所有內存都是一次性分配的,然后初始化類處理類層次結構。
這是對程序方法的理解使得面向對象的方法更容易理解的罕見地方之一。 即使您正在使用OOP,編譯器仍然遵循程序邏輯 - 工作從頭到尾完成。
一個簡單的例子是當編譯器命中private int n = 90
。 首先它為一個整數值分配空間,然后為整數值分配一個標識符,然后為它賦值90.它不能分配值,直到它有兩個空間來粘貼它並知道如何訪問它,也不能訪問不存在的空間。
在這個實例中,派生類Y
構建在基類X
頂部,類似於變量n
在上面示例中的“類” integer
之上構建的方式。 這是由聲明class Y:X
觸發的 - 在它理解如何構建X
之前,編譯器甚至無法開始構建Y
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.