2012-03-01 83 views
1

可以說我有以下幾點:這是通過引用還是按價值傳遞?

class MyClass 
{ 
    // ... 
} 

void doSomething (MyClass instance) 
{ 
    // Is instance passed by reference or by value (copied)? 
} 

void main() 
{ 
    MyClass instance = MyClass(); 

    doSomething(instance); 
} 

doSomething()instance按引用傳遞?或者這個類是否在內存中複製?或者是其他東西?

+0

幕後發生了什麼?整個對象是否在內存中複製? – Cheetah 2012-03-01 21:48:04

+0

你必須看看複製構造函數的作用。 – 2012-03-01 21:49:26

+0

在本例中,你的參數'實例'是由編譯器定義的拷貝構造函數構造的。 – 2012-03-01 21:49:46

回答

5

這是通過值傳遞

void doSomething (MyClass instance) 

這是通過參考

void doSomething (MyClass& instance) 

通過這是通過const引用傳遞

void doSomething (const MyClass& instance) 

MyClass而且不需要通過構建通過分配。 所以:

MyClass mc=MyClass(); 

實際上是相同的:

MyClass mc; //no parens needed for default constructor (no args). 

編輯: 這是由常量引用傳遞給const函數,const函數可以在const對象上調用,因爲它保證不要修改對象狀態。

void doSomething (const MyClass& instance) const 

與許多不太嚴格的語言不同,Const正確性在C++中被認爲是很好的做法。

見我

http://en.wikipedia.org/wiki/Const-correctness

http://www.gotw.ca/gotw/006.htm

+0

除了'doSomething()'方法無法修改'const'關鍵字之外,還有什麼意義呢? – Cheetah 2012-03-01 21:52:39

+0

@Ben它允許臨時對象作爲參數傳遞。 – Marlon 2012-03-01 21:53:40

+0

當函數不需要修改剛剛讀取的對象的狀態時,應該使用Const。你應該把你的函數標記爲const(以min爲單位添加一個例子),然後可以在對象爲const時使用這些函數。 – 111111 2012-03-01 21:53:56

1

如果沒有明確說明,則不作爲參考。它是有價值的。

以下原型是指通過引用傳遞參數:

void doSomething (MyClass& instance) 
{ 
    // Is instance passed by reference or by value (copied)? 
    // In this case, by reference 
} 

事實上,在你的情況下,最有可能創造一個新的對象。我說很可能是因爲,只要可觀察到的行爲是相同的,那就不是。但是,理論上,是的,創建一個新的對象用於函數內部。

新對象是通過調用作爲參數傳遞的對象上的複製構造函數創建的。如果你還沒有定義一個複製構造函數,那麼編譯器就會生成一個默認值,它執行淺拷貝。

+0

「我說很有可能是因爲,只要可觀察到的行爲是相同的,它可能不是」>>不能得到它,你能解釋一下嗎? – 2012-03-01 21:52:23

+0

@ Mr.Anubis編譯器可以優化額外的對象。 – 2012-03-01 21:53:34

+0

有沒有辦法扭轉這種情況。我的意思是,是否有任何方法來編寫'MyClass',如果沒有明確說明,IT是通過引用傳遞的,而不是通過值傳遞的? – Cheetah 2012-03-01 21:57:48

1

是的,它被複制。

當您調用doSomething時,會調用MyClass拷貝構造函數來創建一個新實例。

此實例將在doSomething函數期間保持在範圍內。當函數結束時,此實例將調用MyClass析構函數。

(請注意,如果您沒有編寫複製構造函數,則默認爲您創建一個。)

因此,如果你添加一個明確的拷貝構造函數和析構函數:

class MyClass 
{ 
    public: 
     MyClass() 
     { 
      std::cout << "MyClass constructor" << std::endl; 
     } 
     MyClass(const MyClass& other) 
     { 
       std::cout << "MyClass copy constructor" << std::endl; 
     } 
     MyClass::~MyClass() 
     { 
       std::cout << "MyClass destructor" << std::endl; 
     } 
} 
void doSomething (MyClass instance) 
{ 
    std::cout << "doSomething method"; 
} 

void main() 
{ 
    MyClass instance = MyClass(); 
    std::cout << "invoking doSomething" << std::endl; 
    doSomething(instance); 
    std::cout << "returned from doSomething" << std::endl; 
} 

這將輸出如下:

  • MyClass的構造
  • 調用DoSomething的
  • MyClass的拷貝構造函數
  • doSomething方法
  • MyClass的析構
  • 從doSomething的
  • MyClass的析構函數返回
1

它是爲了複製在堆棧上被傳遞給函數。如果你的類已經達到了一定數量的字節,這可能是非常昂貴的,因爲每個實例變量都必須放在堆棧上。在這種情況下,類的行爲與普通的c結構不同。

所以可以說你對你有2個整型(我假設32位系統)

class A { 
    int a; 
    int b; 
}; 
當您在主聲明它

,堆棧指針爲8個字節的下降。 如果你調用your_function(A),C必須將佈局類複製到堆棧,以便your_function在被調用後可以訪問它。這意味着堆棧指針再次下降8個字節,值從舊值寫入,函數被調用。

與2個實例變量這不是什麼大不了的事。但是你有一個可以保存結構並且可以說20個整數+虛擬表的類的圖像?比我可以是一個非常昂貴的操作。如果通過指針傳遞,堆棧指針必須僅減少4個字節,將其中的類地址複製並調用該函數。當然更便宜。

你可以自己嘗試。只需更改函數內的某個實例變量,並在函數返回後檢查,如果第一個類具有新值或函數調用之前的值。這應該給你答案。

在任何情況下,如果這是你想要的,你應該實現一個拷貝構造函數來處理如何拷貝你的變量。

相關問題