先看看msdn上對建構函式的描述:建構函式是一類特殊的方法,用於初始化型別和建立型別的例項。型別建構函式用於初始化型別中的靜態資料。型別建構函式由公共語言執行庫 (clr) 在建立型別的任何例項之前呼叫。型別建構函式是 static(在 visual basic 中為 shared)方法,不能帶任何引數。例項建構函式用於建立型別的例項。例項建構函式可以帶引數,也可以不帶引數。不帶任何引數的例項建構函式稱為預設建構函式。
先看乙個最簡單的:
public class program
// end main.
}// end class.
class classa
}
這裡什麼都沒做,只是生成了乙個classa例項,下面是il反彙編的建構函式的結果:.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
// end of method classa::.ctor
建構函式的反彙編結果名為 .ctor,可以看出雖然我們什麼都沒做,但是這個函式呼叫了system.object型別的建構函式。
看到這裡想到什麼了嗎?classa和object有神馬關係?沒錯,是繼承,classa預設繼承自object。好吧,再看乙個例子:
public class program
// end main.
}// end class.
class classb //隱式的繼承object
}class classa : classb //繼承classb
}
再看看我們的classa的 .ctor :
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
// end of method classa::.ctor
這次呼叫了classb的建構函式了,那麼classb呢 :
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
// end of method classb::.ctor
又是call指令,不解釋。
有興趣的可以試試更深的繼承樹,結果應該是一樣的
最後來乙個總結吧:c#建立例項的時候其建構函式會遞迴的呼叫父類的建構函式,直至繼承樹的根object。
好吧,當前的討論範圍僅限例項建構函式,而c#中還有一種靜態建構函式,不我還是先繼續說說非靜態的吧。
現在改一改剛才的**:
public class program
// end main.
}// end class.
class classa
}
多了一行欄位的宣告及初始化,注意建構函式裡什麼都沒寫,現在看看a的建構函式的il**:.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
// end of method classa::.ctor
看到那個
ldc.i4 0xabc
了吧,再看看下一行
stfld int32 initializetest.classa::number
,前一行ldc是把乙個常數壓入棧,後一行stfld指令是從棧中獲取值替換例項成員,就是賦值(此處為初始化)。
看來欄位的初始化是建構函式的一部分,且最先執行,在遞迴呼叫父類建構函式之前。
的把這個**再改一次:
public class program
// end main.
}// end class.
class classa
}
注意看il**的變化,和上面對比一下:
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
// end of method classa::.ctor
這次初始化的執行是在呼叫基類建構函式之後進行的,現在再加點語句:
class classa
}
il**:
.method public hidebysig specialname rtspecialname
instance void .ctor() cil managed
// end of method classa::.ctor
大括號內的(我們真正寫在建構函式內的)**是放在最後執行的。
在編譯之後的.ctor方法中,我們使用c#編寫的語句,即那些可以"看得見的**"是放在最後執行的,在這之前是呼叫基類的構造方法,如果在宣告欄位的時候初始化了,那麼初始化的指令在遞迴地呼叫建構函式之前執行。
你可能感覺不是那麼直觀吧,最後這個**有興趣可以自己試一試,改一改:
public class program
// end main.
//只是為了賦值的時候能直**到.
public static int getval(int val)
", val);
return val;
}}// end class.
class classa
}class classb : classa
}class classc : classb
}
繼承樹是 a<-b<-c,字段初始化的順序是cba,而建構函式中的**的執行順序是abc.
《C程式設計伴侶》誕生記
引自圖靈教育陳冰老師的 編輯的話 我第一次看譚老師的 c程式設計 是20年前,那時我17歲,大學一年級。當時感覺這本書很神奇,對程式設計充滿了好奇。同時也感覺這本書有些難,有些地方,比如指標,雖然看過書,也有老師講過了,但依然感覺似懂非懂。還有些知識,書中只講了怎麼做,但沒有講為什麼要這麼做,比如為...
c 物件模型筆記之拷貝建構函式
拷貝建構函式 拷貝建構函式 以乙個物件的內容去初始化另個物件。關鍵在於初始化 有三種情況下會呼叫拷貝建構函式 class x 1 x x x xx x 不是賦值操作而是拷貝建構函式 2 void foo x x 物件引數 3 foobar 返回物件 如果類沒有提供顯示的拷貝建構函式,編譯器採用的是位...
C 之物件的引用與建構函式
定義 person 類,設定屬性 年齡。namespace 物件的引用 class person public person int age 帶引數的建構函式 定義 person 類,設定屬性 姓名,年齡。設定不帶引數的建構函式 設定帶名字的建構函式 設定帶年齡的建構函式 namespace 建構函...