我們寫一個函數,比如 objclass fun(objclass obj); objclass是類名,obj是對象,fun是函數名。
然後調用此函數,編譯器分兩個步驟:
1.每次通過值傳遞的方式給函數傳遞一個對象時,都會建立一個該對象的拷貝。
2.每次通過值從函數返回一個對象時,也會建立另一個拷貝。
也就是說調用一次此函數,系統會自動建立兩次的對象拷貝,然後再調用兩次析構函數釋放對象的拷貝。
我們知道當調用函數的時候,這些對象被複制到棧中,這樣做會費時且佔用內存,當使用用戶定義的大對象時,這種拷貝帶來的內存開銷是非常顯著的。當時用用戶建立的類時,每次生成這種臨時的拷貝都要調用一個特殊的構造函數:複製構造函數。當函數返回時,對象的臨時拷貝被刪除,此時需要調用對象的析構函數。如果返回對象時通過值傳遞的方式,那麼必須建立對象的拷貝,然後再刪除。對於很大的對象,調用構造函數和析構函數在速度和內存方面都會造成很大的開銷。
爲了說明這一點見下面的例子:
#include <iostream>
using namespace std;
class class_A
{
public:
class_A()
{
cout<<"class_A 構造函數..."<<endl;
}
class_A(class_A &)
{
cout<<"class_A 複製構造函數..."<<endl;
}
~class_A()
{
cout<<"class_A 析構函數..."<<endl;
}
};
//-------------------------------------------------------------------------------------------
class_A funOne(class_A obj);
class_A *funTwo(class_A *obj);
class_A funOne(class_A obj)
{
cout<<"函數funOne返回..."<<endl;
return obj;
}
class_A *funTwo(class_A *obj)
{
cout<<"函數funTwo返回..."<<endl;
return obj;
}
//-------------------------------------------------------------------------------------------
int main(int argc, char *argv[])
{
//調用 class_A的構造函數
class_A abc;
//-------------------------------------------------------------------------------------------
cout<<"調用函數funOne..."<<endl;
//1.採用值傳遞的方式傳遞 class_A類的對象,因此在棧中會建立一個對象的拷貝,作爲
//被調用函數的局部對象,這樣就調用了複製構造函數。
//2.當函數返回的時候,函數採取值傳遞的方式返回 class_A類的對象,這樣又會建立對象
//的另一個拷貝,再次調用複製構造函數。
funOne(abc);
//1.funOne()返回值不賦給任何對象,因此這個返回的臨時值就被丟棄了,這時調用析構函數。
//2.funOne()結束之後,因此它的局部拷貝的作用域也隨之結束和被刪除,這時又一次調用了
//析構函數。
//-------------------------------------------------------------------------------------------
cout<<"調用函數funTwo..."<<endl;
//傳遞參數採用引用的方式,因此,沒有對象進行拷貝,也就沒有輸出。
funTwo(&abc);
//返回 class_A類的對象,由於這一次依然採用引用傳遞的方式,因此還是沒有調用構造函數和析構函數。
//-------------------------------------------------------------------------------------------
system("PAUSE");
return EXIT_SUCCESS;
}
以上code可以直接複製使用~~