第九章 方法
一、 實(shí)例構(gòu)造器
1、 前面提到用new操作符創(chuàng)建對(duì)象時(shí)的三部曲:
l 為對(duì)象分配內(nèi)存
l 初始化對(duì)象的附加成員(方法表指針和SyncBlockIndex)
l 調(diào)用實(shí)例構(gòu)造器初始化實(shí)例狀態(tài)
在分配內(nèi)存時(shí),系統(tǒng)將所有內(nèi)存位置均置為0值,這就是為什么字段初始化而未賦值時(shí)均為0或null值。
不調(diào)用實(shí)例構(gòu)造器的情況:
l 調(diào)用Object.MemberwiseClone()方法創(chuàng)建實(shí)例(分配內(nèi)存;初始化附加成員;將源對(duì)象字節(jié)拷貝到新創(chuàng)建的對(duì)象)
l 反序列化對(duì)象時(shí)
2、 為避免為實(shí)例字段產(chǎn)生過(guò)多的構(gòu)造器代碼,應(yīng)避免在聲明字段時(shí)為字段符初值,而是在無(wú)參構(gòu)造器中為它們符初值,在其他重載的構(gòu)造器中調(diào)用無(wú)參構(gòu)造器。
3、 值類型實(shí)例構(gòu)造器
l C#編譯器不會(huì)自動(dòng)調(diào)用其構(gòu)造器,必須顯式調(diào)用構(gòu)造器才能起作用
l C#編譯器不允許為值類型定義無(wú)參實(shí)例構(gòu)造器(下面會(huì)介紹可以定義無(wú)參類型構(gòu)造器)
l 不能為結(jié)構(gòu)中的字段在聲明的同時(shí)賦初值,可通過(guò)定義帶參構(gòu)造器的方式進(jìn)行
l 必須在結(jié)構(gòu)的構(gòu)造器中為所有字段賦初值
二、 類型構(gòu)造器
1、 類型構(gòu)造器的一些限制:
l 不能帶任何參數(shù)
l 類型構(gòu)造器總為私有的,不能用其他訪問(wèn)修飾符
2、類型構(gòu)造器被調(diào)用的時(shí)機(jī):
l 第一個(gè)實(shí)例被創(chuàng)建,或者類型的第一個(gè)字段或成員第一次被訪問(wèn)之前
l 非繼承靜態(tài)字段被第一次訪問(wèn)之前
類型構(gòu)造器在類型的生命周期中只被調(diào)用一次;
3、一些限制:
l 若類型構(gòu)造器中拋出異常,則該類型變成不可訪問(wèn),訪問(wèn)其中的任何字段或方法均會(huì)拋出System.TypeInitializationException異常
l 類型構(gòu)造器只能訪問(wèn)類型的靜態(tài)字段
l 類型構(gòu)造器不應(yīng)該調(diào)用基類型的類型構(gòu)造器,因靜態(tài)字段并非繼承而是編譯時(shí)靜態(tài)綁定
三、 操作符重載
1、 操作符重載
C#中對(duì)操作符重載的一些限制:
l 必須聲明為public static
l 必須有一個(gè)參數(shù)為操作符所屬類型
l 不能改變操作符原始定義的引數(shù)個(gè)數(shù)
l 若定義了true操作符也必須同時(shí)定義false操作符,二者都必須返回bool值
l ++、--操作符必須返回其所隸屬之類型的一個(gè)實(shí)例
l 可被重載的一元操作符:+、-、!、~、++、--、true、false
l 可被重載的二元操作符:+、-、*、/、%、!、^(異或)、<、>、<<、>>、==、!=、<=、>=
l 不允許被重載的操作符:&&、||、=、?:、+=、-=、/=、%=、|=、^=、<<=、>>=,實(shí)際上其中一些“復(fù)式操作符”在二元操作符被重載后自動(dòng)生成,而不能顯式定義
l 必須成對(duì)重載的操作符:(== ,!=)、(<,>)、(<=,>=)
l ++、--操作符重載時(shí)不能區(qū)分其為前置或后置的
2、 操作符重載與語(yǔ)言互操作性
編譯器會(huì)為重載的操作符生成一個(gè)特殊名稱的方法,如+(加)操作符生成op_Addition()方法,并為該方法的定義條目上加上specialname標(biāo)記。當(dāng)某種語(yǔ)言不能進(jìn)行操作符重載時(shí),可以直接定義具有該特殊名稱的方法,以在其他語(yǔ)言中調(diào)用;或直接調(diào)用具有該特殊名稱的方法以適應(yīng)某種語(yǔ)言不能解析操作符的限制。如:vb中不能重載操作符,可顯式定義op_Addition()方法以在C#中調(diào)用;C#中定義的+操作符不能被VB識(shí)別,可顯式調(diào)用op_Addition()方法獲得同樣的功能。
四、 轉(zhuǎn)換操作符
轉(zhuǎn)換操作符的一些限制:
l 必須為public static
l 必須指定關(guān)鍵字implicit或explicit,原則為:從本類型轉(zhuǎn)換為其他類型使用implicit,將其他類型轉(zhuǎn)換為本類型用explicit,不能都使用implicit
五、 方法參數(shù)
1、 引用參數(shù)
l 缺省情況下為值傳遞
l 標(biāo)志為out的參數(shù),在調(diào)用方法前不必初始化,但返回之前必須賦值,沒(méi)有被初始化的參數(shù)是不能被使用
l 標(biāo)志為ref的參數(shù),在調(diào)用方法前必須初始化,否則觸發(fā)編譯錯(cuò)誤
l 可以使用ref或out來(lái)進(jìn)行方法的重載,但不能通過(guò)區(qū)分ref和out來(lái)重載方法
l 按引用方式傳遞的變量(實(shí)參)必須和方法聲明的參數(shù)(形參)類型完全相同,否則觸發(fā)編譯錯(cuò)誤。
2、 可變數(shù)目參數(shù)
使用params關(guān)鍵字及對(duì)象數(shù)組的方式指定可變參數(shù)序列。一些限制:
l 只有方法的最后一個(gè)參數(shù)才能使用可變數(shù)目參數(shù)
六、 虛方法
1、 虛方法的調(diào)用機(jī)理
CLR使用以下兩個(gè)IL指令調(diào)用方法:
u call 根據(jù)類型(即引用的靜態(tài)類型、聲明類型)來(lái)調(diào)用一個(gè)方法
u callvirt 根據(jù)對(duì)象(即引用的動(dòng)態(tài)類型、實(shí)際類型)來(lái)調(diào)用一個(gè)方法
對(duì)于虛方法使用call來(lái)調(diào)用的情況有:
l base.虛方法(),
l 密封類型引用虛方法,因?yàn)闆](méi)有必要檢驗(yàn)密封類型的實(shí)際類型
l 值類型,避免被裝箱
使用callvirt調(diào)用非虛方法的情況:
l 應(yīng)用變量為null時(shí),使用callvirt才會(huì)拋出System.NullReferenceException異常,而call不會(huì)拋出
無(wú)論call或callvirt調(diào)用方法,均會(huì)有一個(gè)隱含的this指針作為方法的第一個(gè)參數(shù),它指向正在操作的對(duì)象
2、 虛方法的版本控制:
用下面的例子說(shuō)明:
using System;
class BaseClass
{
public void NonVirtualFunc()
{
Console.WriteLine("Non virtual func in base class");
}
public virtual void VirtualFunc()
{
Console.WriteLine("Virtual func in base class");
}
}
class DevicedClass : BaseClass
{
//若不使用new 關(guān)鍵字則編譯器會(huì)有warning:
//“DevicedClass.NonVirtualFunc()”上要求關(guān)鍵字
//new,因?yàn)樗[藏了繼承成員“BaseClass.NonVirtualFunc()”
public new void NonVirtualFunc()
{
Console.WriteLine("Non virtual func in deviced class");
}
//若不添加關(guān)鍵字override或new,則編譯器會(huì)有warning:
//“DevicedClass.VirtualFunc()”將隱藏繼承的成員“BaseClass.VirtualFunc()
//”。若要使當(dāng)前成員重寫該實(shí)現(xiàn),請(qǐng)?zhí)砑雨P(guān)鍵字 override。否則,添加關(guān)鍵字
//new。
public override void VirtualFunc()
{
Console.WriteLine("Virtual func in deviced class");
}
}
class TestClass
{
public static void Main()
{
//派生類實(shí)例調(diào)用 非虛 及 虛函數(shù)
DevicedClass dc = new DevicedClass();
dc.NonVirtualFunc();
dc.VirtualFunc();
//基類實(shí)例調(diào)用 非虛 及 虛函數(shù)
BaseClass bc = new BaseClass();
bc.NonVirtualFunc();
bc.VirtualFunc();
//指向派生類實(shí)例的基類引用 調(diào)用 非虛 及 虛函數(shù)
BaseClass bc1 = dc;
bc1.NonVirtualFunc();
bc1.VirtualFunc();
}
}
/*
在虛函數(shù)上使用關(guān)鍵字override的運(yùn)行結(jié)果:
Non virtual func in deviced class
Virtual func in deviced class
Non virtual func in base class
Virtual func in base class
Non virtual func in base class
Virtual func in deviced class
*/
/*
在虛函數(shù)上使用關(guān)鍵字new的運(yùn)行結(jié)果
Non virtual func in deviced class
Virtual func in deviced class
Non virtual func in base class
Virtual func in base class
Non virtual func in base class
Virtual func in base class
*/
由上可見:new 和 override在派生類中協(xié)調(diào)版本的控制,在第七章中已經(jīng)看到oeverride只能用于virtual方法,new則可用于非虛或虛方法,以實(shí)現(xiàn)隱藏基類中的同名方法。在虛函數(shù)上使用override,重寫了基類的方法,并無(wú)隱藏,這也就實(shí)現(xiàn)了多態(tài)。我們可設(shè)想這樣的結(jié)論:new使用call指令調(diào)用靜態(tài)類型的方法,而override使用callvirt指令調(diào)用動(dòng)態(tài)類型的方法。
希望這個(gè)例子對(duì)您的理解
|
溫馨提示:喜歡本站的話,請(qǐng)收藏一下本站!