物件作為引數和返回值 複製(拷貝)建構函式
阿新 • • 發佈:2018-12-13
先看一道搜狗的校園招聘題: 不考慮任何編譯器優化(如:NRVO),下述程式碼的第10行會發生
#include <stdio.h>//1
class B//2
{//3
};//4
B func(const B& rhs){//5
return rhs;//6
}//7
int main(int argc,char **argv){//8
B b1,b2;//9
b2=func(b1);//10
}//11
答案是 :一次拷貝建構函式,一次解構函式,一次賦值運算子。 為了說明這個問題,我們把程式碼改寫一下,如下
#include<iostream> #include<stdio.h> using namespace std; class B { public: B() { cout<<"建構函式"<<endl; } ~B() { cout<<"解構函式"<<endl; } B(const B& b) { cout<<"拷貝建構函式"<<endl; } B& operator=(const B& b) { cout<<"賦值建構函式"<<endl; } }; B func1(B& b) { return b; } B func2(B b) { return b; } B& func3(B b) { return b; } int main() { B b1,b2; cout<<endl; cout<<"以下是func1的結果:"<<endl; b2 = func1(b1); cout<<endl; cout<<"以下是func2的結果:"<<endl; b2 = func2(b1); cout<<endl; cout<<endl; cout<<"以下是func3的結果:"<<endl; b2 = func3(b1); cout<<endl; return 0; }
結果如下: 主要考察的是賦值建構函式的用法,使用賦值建構函式有3中情況: 1 明確表示由一個物件初始化另一個物件時: B b1; B b2(b1);
2 當物件作為函式實參傳遞給函式形參時,會呼叫拷貝建構函式,生成一個無名的區域性物件,但如果引數是引用或者是指標,則不用呼叫拷貝建構函式: func2(b1)
3 當一個自動儲存類物件作為函式返回值時,會呼叫拷貝建構函式生成一個無名的物件,返回給函式,,但如果返回值型別是引用或者指標,則 不呼叫: return b;
對於func1, 引數是引用型別,不呼叫建構函式,不生成臨時物件 在返回物件時,首先要用拷貝建構函式生成一個無名物件並返回給呼叫函式,所以有一次拷貝建構函式, 接著執行賦值操作,呼叫賦值運算子, 此時,func1執行結束,無名的物件被釋放,呼叫一次解構函式。
對於func2, 傳遞引數時呼叫一次拷貝建構函式,生成一個無名物件, 返回時,呼叫一次拷貝建構函式,又生成一個無名物件, 接著是賦值運算子,呼叫賦值運算子 func2結束,釋放無名物件,因為有兩個,所以呼叫兩次解構函式。
對於func3: 傳遞引數時呼叫一次拷貝建構函式,生成一個無名物件, 返回時,因為是引用,所以不呼叫,也不生成物件 接著是賦值運算子,呼叫賦值運算子 func3結束,釋放無名物件,因為只有一個,所以呼叫一次解構函式
注意:在func3中,有些編譯器可能編譯出錯。因為無名變數是區域性變數,在函式執行結束時就會釋放,引用這樣的變數會導致程式出現錯誤。