前言
大家都知道類的繼承規則:
1、派生類自動包含基類的所有成員。但對于基類的私有成員,派生類雖然繼承了,但是不能在派生類中訪問。
2、所有的類都是按照繼承鏈從頂層基類開始向下順序構造。最頂層的基類是system.object
類,所有的類都隱式派生于它。只要記住這條規則,就能理解派生類在實例化時對構造函數的調用過程。
不知道大家在使用繼承的過程中有木有遇到過調用構造函數時沒有按照我們預期的那樣執行呢?一般情況下,出現這樣的問題往往是因為類繼承結構中的某個基類沒有被正確實例化,或者沒有正確給基類構造函數提供信息,如果理解在對象生命周期的這個階段發生的事情,將更利于解決此類問題。
為了實例化派生的類,必須先實例化它的基類。而要實例化這個基類。又必須要實例化這個基類的基類,這樣一直到實例化system.object
(所有類的跟)為止,結果無論使用什么構造函數實例化一個類,總是首先調用system.object.object()
.
下面一個示例演示執行順序:
基類:
1
2
3
4
5
6
7
8
9
10
11
|
public class mybaseclass { public mybaseclass() { console.writeline( "i am mybaseclass()" ); } public mybaseclass( int i) { console.writeline( "i am mybaseclass(int i)" ); } } |
派生類:
1
2
3
4
5
6
7
8
9
10
11
12
|
public myderivedclass() { console.writeline( "i am myderivedcalss()" ); } public myderivedclass( int i) { console.writeline( "i am myderivedclass(int i)" ); } public myderivedclass( int i, int j) { console.writeline( "i am myderivedclass(int i,int j)" ); } |
接下來我們在main函數中以不帶參數的構造函數實例化myderivedclass:
1
|
myderivedclass myobj = new myderivedclass(); |
運行程序,控制臺輸出如下:
從結果可以看出,執行順序先是基類構造的函數,接下來才是派生類的構造函數,即
1.執行system.object.object()
構造函數(object比較特殊,所有類的基類,一般可以不考慮,但是得知道它也是被執行了的)
2.執行mybaseclass.mybaseclass()
構造函數
3.執行myderivedclass.myderivedclass()
構造函數
如果我們以帶一個參數的構造函數實例化myderivedclass:
1
|
myderivedclass myobj = new myderivedclass(4); |
運行程序,控制臺輸出如下:
可以看出執行順序如下:
1.執行system.object.object()
構造函數
2.執行mybaseclass.mybaseclass()
構造函數
3.執行myderivedclass.myderivedclass(int i)
構造函數
同理如果我們以帶兩個參數的構造函數實例化myderivedclass
1
|
myderivedclass myobj = new myderivedclass(4,8); |
運行程序,控制臺輸出如下:
可以看出執行順序如下:
1.執行system.object.object()
構造函數
2.執行mybaseclass.mybaseclass()
構造函數
3.執行myderivedclass.myderivedclass(int i,int j)
構造函數
大多數情況下這個都能正常工作,但是有時我們需要對發生的事件進行更多的控制。比如我們想得到如下所示的執行順序:
1.執行system.object.object()構造函數
2.執行mybaseclass.mybaseclass(int i)
構造函數
3.執行myderivedclass.myderivedclass(int i,int j)
構造函數
使用這個順序,可以把使用int i參數的代碼放到mybaseclass(int i)
中,myderivedclass(int i,int j)
只需要處理int j(假設int i參數在mybaseclass和 myderivedclass里含義是一樣的)
為此,只需要使用構造函數初始化器,把代碼放到方法定義的冒號后面,如在派生類的構造函數中指定所使用的基類的構造函數,如下所示:
1
2
3
4
|
public myderivedclass( int i, int j) : base (i) { console.writeline( "i am myderivedclass(int i,int j)" ); } |
其中,base關鍵字指定在實例化過程中使用具有指定參數的構造函數。這里使用了int參數,其值通過i傳遞給myderivedclass構造函數,所以將使用mybaseclass(int i)
,這樣就不會調用mybaseclass()
了,我們重新執行下前面兩個參數的實例化代碼,就可以看出執行結果確實如此:
除了base關鍵字,還可以使用this關鍵字用作構造函數初始化器,這個關鍵字指定在調用指定的構造函數前,實例化過程對當前類使用非默認的構造函數。例如:
1
2
3
4
|
public myderivedclass(): this (5,6) { console.writeline( "i am myderivedcalss()" ); } |
使用myderivedcalss()
構造函數實例化,執行順序是:
1.執行system.object.object()
構造函數
2.執行mybaseclass.mybaseclass(int i)
構造函數
3.執行myderivedclass.myderivedclass(int i,int j)
構造函數
4.執行myderivedclass.myderivedclass()
構造函數
總之呢,無論派生類上使用什么樣的構造函數(默認的or不是默認的),除非明確指定(如使用base關鍵字),否則就先調用用基類的默認構造函數。
總結
以上就是這篇文章的全部內容了,希望本文的內容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:https://www.cnblogs.com/yixuanhan/p/9596454.html