驗證示例的**如下:
usingsystem;
public
class
argsbyreforvalue
static
void
changebyint(
inti)
static
void
changebystruct(person_val p_val)
static
void
changebyclass(person_ref p_ref)
static
void
changebyclassref(
refperson_ref p)
}
public
struct
person_val
public
class
person_ref
執行結果如下:
看起來似乎上面**中實驗3和實驗4是一樣的,即對於類(class)來說,不管加不加ref或out,都是傳引用呼叫。
其實,這只是表面的現象,只要稍微改一下**,結果就不一樣了。
修改上面**,再增加兩個實驗。
usingsystem;
public
class
argsbyreforvalue
static
void
changebyint(
inti)
static
void
changebystruct(person_val p_val)
static
void
changebyclass(person_ref p_ref)
static
void
changebyclassref(
refperson_ref p)
static
void
changebyclassnew(person_ref p_ref_new)
static
void
changebyclassrefnew(
refperson_ref p_new)
}
public
struct
person_val
public
class
person_ref
則執行結果為:
實驗5的執行結果似乎說明即使引數是類(class),只要不加ref,也是傳值呼叫。
下面就引出了我的理解。
2. 沒有ref時,即使引數為引用型別(class)時,也可算是一種傳值呼叫
引數為引用型別時,傳遞的是該引用型別的位址的乙份拷貝,「該引用型別的位址的乙份拷貝」即為傳值呼叫的「值」。
注意這裡說傳遞的是該引用型別的位址的乙份拷貝,而不是引用型別的位址。
下面將用圖的形式來說明以上實驗3,實驗5和實驗6中記憶體的情況。
2.1 首先是實驗3
實驗3的記憶體圖如下,實參是函式changebyclass外的person_ref物件,形參是函式changebyclass內的person_ref物件。
從圖中我們可以看出實參new出來之後就在託管堆上分配了記憶體,並且在棧上儲存了物件的指標。
呼叫函式changebyclass後,由於沒有ref引數,所以將棧上的實參p_val拷貝了乙份作為形參,注意這裡p_val(實參)和p_val(形參)是指向託管堆上的同一位址。
所以說沒有ref時,即使引數為引用型別(class)時,也可算是一種傳值呼叫,這裡的值就是託管堆中物件的位址(0x1000)。
呼叫函式changebyclass後,通過p_val(形參)修改了name屬性的值,由於p_val(實參)和p_val(形參)是指向託管堆上的同一位址,所以函式外的p_val(實參)的name屬性也被修改了。
2.2 然後是實驗5
上面的實驗3從執行結果來看似乎是傳引用呼叫,因為形參的改變導致了實參的改變。
下面的實驗5就可以看出,p_val(形參)和p_val(實參)並不是同乙個變數,而是p_val(實參)的乙個拷貝。
從圖中可以看出第一步還是和實驗3一樣,但是在呼叫函式changebyclassnew後,就不一樣了。
函式changebyclassnew中,對p_val(形參)重新分配了記憶體(new操作),使其指向了新的位址(0x1100),如下圖:
所以p_val(形參)的name屬性改了時候,p_val(實參)的name屬性還是沒變。
2.3 最後是實驗6
我覺得實驗6是真正的傳引用呼叫。不廢話了,直接上第乙個圖。
引數中加了ref關鍵字之後,其實傳遞的不是託管堆中物件的位址(0x1000),而是棧上p_val(實參)的位址(0x0001)。
所以這裡實參和形參都是棧上的同乙個東西,沒有什麼區別了。我覺得這才是真正的傳引用呼叫。
然後呼叫了函式changebyclassrefnew,函式中對p_val(形參)重新分配了記憶體(new操作),使其指向了新的位址(0x1100)。
由於p_val(形參)就是p_val(實參),所以p_val(形參)的name屬性改變後,函式changebyclassrefnew外的p_val(實參)的name屬性也被改變了。
而原先分配的物件(位址0x1000)其實已經沒有被引用了,隨時會被gc**。
3. 結論
如果呼叫的函式中對引數重新進行了位址分配(new操作),那麼執行結果類似傳值呼叫
如果呼叫的函式中沒有對引數重新進行了位址分配,直接就是使用了傳遞的引數,那麼執行結果類似傳引用呼叫
深刻理解C 的傳值呼叫和傳引用呼叫
值呼叫和傳引用呼叫是幾乎所有主流語言都會涉及到的問題,下面我談談我對c 中傳值呼叫和傳引用呼叫的理解。1.一般對c 中傳值呼叫和傳引用呼叫的理解 如果傳遞的引數是基元型別 int,float等 或結構體 struct 那麼就是傳值呼叫。如果傳遞的引數是類 class 那麼就是傳引用呼叫。如果傳遞的引...
傳值呼叫和引用呼叫
值呼叫是指當發生函式呼叫時候,給形參分配記憶體空間,並用實參來初始化形參 直接將實參的值傳遞給形參 這一過程是引數值的單向傳遞過程,一旦形參獲得了值,便於實參脫離了關係,此後無論形參發生了什麼變化,都不影響實參了.引用呼叫將引用作為形參,在執行主調函式中的呼叫語句時候,系統自動用實參來初始化形參.這...
引用呼叫和傳值呼叫
1.傳值呼叫又分為資料傳值呼叫和位址傳值呼叫。資料傳值呼叫方式是將實參的資料值傳遞給形參。實參和形參在棧空間內的位址不相同,改變形參值不影響實參值 位址傳值呼叫方式是將實參的位址值傳遞給形參,實參和形參在棧空間內共用同一位址,改變形參值就可改變實參值。2.引用呼叫是將實參變數值傳遞給形參,而形參是實...