【转】继承过程中 父类子类的 字段方法 内存分配 (非java语言)
名人名言:思想好比火星:一顆火星會(huì)點(diǎn)燃另一顆火星。一個(gè)深思熟慮的教師和班主任,總是力求在集體中創(chuàng)造一種共同熱愛(ài)科學(xué)和渴求知識(shí)的氣氛,使智力興趣成為一些線索,以其真摯的、復(fù)雜的關(guān)系——即思想的相互關(guān)系把一個(gè)個(gè)的學(xué)生連接在一起。——蘇霍姆林斯基?
首先給出部分代碼,由此來(lái)分析一下運(yùn)行過(guò)程中對(duì)象、字段的創(chuàng)建過(guò)程,和編譯過(guò)程中方法列表的創(chuàng)建過(guò)程。
public class Animal
{
public virtual void Eat()
{
Console.WriteLine("Animal Eat" );
}
public virtual void Sleep()
{
Console.WriteLine("Animal Sleep" );
}
public void Play()
{
Console.WriteLine("Animal Play" );
}
}
public class Cat : Animal
{
public override void Eat()
{
base.Eat();//調(diào)用父類方法
Console.WriteLine("Cat Eat" );
}
public override void Sleep()
{
Console.WriteLine("Cat Sleep" );
base .Sleep();
}
}
?
以上代碼 如果在Main方法中 通過(guò) Animal a = new Cat(); 來(lái)實(shí)現(xiàn)一個(gè)父類引用子類對(duì)象。
?
這句話首先是創(chuàng)建了一個(gè)Animal類型的a的引用,然后 new Cat();創(chuàng)建了一個(gè)Cat的對(duì)象,最后把這個(gè)a這個(gè)引用指向了
????????????? new Cat();這個(gè)對(duì)象的地址。在這個(gè)對(duì)象創(chuàng)建的過(guò)程中其實(shí)有很多步驟
?????????????
????????????? 首次訪問(wèn):(在此沒(méi)有顯示的寫(xiě)出類中的構(gòu)造方法)
?????????????????? 順序:子類的靜態(tài)字段==》子類靜態(tài)構(gòu)造==》子類非靜態(tài)字段==》父類的靜態(tài)字段==》父類的靜態(tài)構(gòu)造==》父類的非靜態(tài)字段
???????????????????????????? ==》父類的構(gòu)造函數(shù)==》子類的構(gòu)造函數(shù)
?????????????????????????
????????????? 非首次訪問(wèn):順序是一樣的,只不過(guò)少了中間靜態(tài)字段和構(gòu)造的過(guò)程
??????????????
???????????? 這個(gè)過(guò)程依次類推直到遞歸到Object結(jié)束(在次過(guò)程中也是依次給父類分配內(nèi)存的過(guò)程),且字段的在內(nèi)存中的存儲(chǔ)順序是由上到下排列,object類的字段 排在最前面,
????????????? 原因是如果父類和子類出現(xiàn)了同名字段,則在子類對(duì)象創(chuàng)建時(shí),編譯器會(huì)自動(dòng)認(rèn)為這是兩個(gè)不同的字段而加以區(qū)別。?
??????????????
????????????? 說(shuō)了對(duì)象的創(chuàng)建,其次是方法列表的創(chuàng)建:
????????????? 方法列表的創(chuàng)建是在編譯時(shí)創(chuàng)建的,而對(duì)象的創(chuàng)建是在運(yùn)行時(shí),對(duì)象的創(chuàng)建是為了給方法列表一個(gè)引用的指針,使其它們動(dòng)態(tài)關(guān)聯(lián)起來(lái)。
??????????????方法列表的創(chuàng)建順序跟字段的的順序是一樣的,也是先父類后子類。(override 和 new 的不同 new主要是會(huì)阻斷繼承樹(shù),和隱藏父類方法,創(chuàng)建子類和父類同名的方法)
????????????? 父先子后的原因是:在編譯時(shí)創(chuàng)建方法列表的過(guò)程是,先生成父類的方法列表,而后在生成子類的方法列表的時(shí)候,會(huì)把父類的方法復(fù)制一份
????????????? 出來(lái),然后拿子類的方法去和父類的比較,如果發(fā)現(xiàn)同名的方法,則看子類的方法修飾符是override 還是 new,如果是override 則覆蓋父類
????????????? 同名的方法(以上所說(shuō)的父類方法皆是virtual方法,并且這里說(shuō)的覆蓋只是說(shuō)覆蓋方法的實(shí)現(xiàn),而并沒(méi)有覆蓋父類的方法列表,通過(guò)base.父類方法名還是可以調(diào)用父類的方法),
????????????? 如果是new? 則在內(nèi)存中的不同位置創(chuàng)建一個(gè)同名的方法。 不同名的,則直接創(chuàng)建。
?
???? 完成之后,我們可以通過(guò) a這個(gè)引用來(lái)來(lái)調(diào)用Cat中的方法。
?
1.思考:如果把上例中Animal的play方法移到Cat中,在Main方法中打算通過(guò)a.Paly();來(lái)調(diào)用子類的Paly方法會(huì)發(fā)生什么現(xiàn)象? 會(huì)編譯不通過(guò),為什么呢?
?
按理說(shuō)子類就是用來(lái)擴(kuò)展父類的,理論上也允許子類有自己的特性啊(方法、字段……)。但問(wèn)題不是出在子類,而是出在了調(diào)用的位置,不能通過(guò)a.Play();來(lái)調(diào)用這個(gè)方法,可能大家又不解了,會(huì)想 a就是通過(guò) new Cat();這個(gè)對(duì)象啊出來(lái)的,為什么不能調(diào)用自己的方法勒,一層層的,最終我們找到原因是在 Animal a 這個(gè)申明引用的位置。
?
在此要引入OO 的一個(gè)原則: 關(guān)注對(duì)象原則——調(diào)用子類還是父類的方法,取決于創(chuàng)建的對(duì)象是子類對(duì)象還是父類對(duì)象,而不是它的引用類型,而引用指針類型不同的區(qū)別決定了不同的對(duì)象在方法表中不同的訪問(wèn)權(quán)限。
?
由此結(jié)合:子類可以調(diào)用父類方法和字段,而父類不能調(diào)用子類方法和字段? 這個(gè)概念。就可以知道原因了。
?
在說(shuō)說(shuō)OO中的另一個(gè)原則:就近原則——對(duì)于同名字段或者方法,編譯器是按照其順序查找來(lái)引用的,也就是首先訪問(wèn)離它創(chuàng)建最近的字段或者方法。先貼一段代碼,然后通過(guò)代碼來(lái)分析。
?View Code?
?
class Program
{
static void Main(string [] args)
{
Animal a = new Cat();
// MemberInfo[] m = a.GetType().GetMembers();
// foreach (var item in m)
// {
// Console.WriteLine(item.Name);
// }
// a.Eat();
// a.Play();
//a.Sleep();
Console.WriteLine(a.AnimalName);
}
}
public class Animal
{
public string AnimalName = "Animal" ;
}
public class Cat : Animal
{
public string AnimalName = "Cat" ;
}
?
在代碼的Main方法中??Animal a = new Cat();? 這個(gè)A是Animal 類型的,結(jié)合文章開(kāi)始將的 在編譯和運(yùn)行過(guò)程中 子類、父類 的字段和方法以及實(shí)例化時(shí)候在內(nèi)存中分配的先后位置可以得出:Animal 類中的 AnimalName 在內(nèi)存中的位置一定位于 Cat中AnimalName在內(nèi)存中的位置的前面,根據(jù)就近原則打印出的應(yīng)該是Animal。
?
以上文章大致概括了在繼承過(guò)程中的?在編譯和運(yùn)行過(guò)程中 子類、父類 的字段和方法以及實(shí)例化時(shí)候在內(nèi)存中分配 和 執(zhí)行的先后,以及兩個(gè)原則,如有錯(cuò)誤或者不足的地方請(qǐng)拍磚。后續(xù)后更深入的學(xué)習(xí)oo中的其它內(nèi)容。
總結(jié)
以上是生活随笔為你收集整理的【转】继承过程中 父类子类的 字段方法 内存分配 (非java语言)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 月薪6000存钱技巧!教你如何告别死工资
- 下一篇: 《暗黑4》全新实机演示 大风车吱呀吱呀转