昨天看到一個moto公司的面試題,題目如下:
#include <iostream>
Using namespace std ;
class human
{
public:
human()
{
human_num++;
}
static int human_num;
~human()
{
human_num--;
print();
}
void print()
{
cout<<"human nun is: "<<human_num<<endl;
}
protected:
private:
};
int human::human_num = 0;
human f1(human x)
{
x.print();
return x;
}
int main(int argc, char* argv[])
{
human h1;
h1.print();
human h2 = f1(h1);
h2.print();
return 0;
}
寫出程式的輸出結果。。。。。只 知道輸出5行,但是不知道每行 human_num的值是多少??
我們先不看這個題目,我們先來瞭解一下建構函式在按值傳向函數,以及按值從函數返回的時候會發生什麼:
1、將對象按值傳給函數的時候,首先會建立該對象的一個副本,將這個副本傳給函數,但是在建立這個副本的時候,不會調用建構函式,而在這個函數返回的時候會調用解構函式。
2、函數按值返回對象的時候,也會建立返回對象的一個副本,同樣的也不會調用建構函式,在返回後調用解構函式銷毀該對象。
我們先來看下面的一個程式:
/*
Constructor and destructor
*/
#include <iostream>
#include <string>
using namespace std ;
class test
{
public:
//Constructor
test( string s ):str(s)
{
cout << "Constructing " << endl ;
}
//Destructor
~test()
{
cout << "Destructing " << endl ;
}
string getValue()
{
return str ;
}
private:
string str ;
} ;
void display( test t )
{
cout << t.getValue() << endl ;
}
test getTest()
{
return test("Jun") ;
}
void main()
{
//這裡很顯然調用了一次建構函式,程式會輸出:constructing
test te = test("Guo") ;
//在向函數按值傳對象的時候,會建立傳遞的對象的副本
//但是此時不會調用建構函式。不會有constructing輸出
display(te) ;
//在函數返回的時候,會調用其destructor銷毀剛才的副本
//程式輸出:Destructing
getTest() ;
//在getTest裡面我們建立了一個對象,因此會有一次constructor的調用
//程式輸出:constructing ,我們知道在程式返回的時候,會產生一個副本返回
//因此實際上在函數裡面會有destructor的調用,然後再返回到main函數裡面
//的對象也會被destructed,因此會再次輸出destructing,最後銷毀最初的
//對象。
}
//最終程式的結果:
//constructing
//Destructing
//Guo
//destructing
//constructing
//destructing
//destructing
//destructing
回過頭來我們看看上面的例子:
#include <iostream>
Using namespace std ;
class human
{
public:
human()
{
human_num++;
}
static int human_num;
~human()
{
human_num--;
print();
}
void print()
{
cout<<"human nun is: "<<human_num<<endl;
}
protected:
private:
};
int human::human_num = 0;
human f1(human x)
{
x.print();
return x;
}
int main(int argc, char* argv[])
{
human h1;
//h1被構造,human_num = 1
h1.print();
//h1作一個拷貝,然後將拷貝傳入函數,沒有建構函式被調用,因此會輸出1
//返回的是一個對象,因此還是會做一個拷貝,然後返回,此時調用一次溪溝函數,臨時拷貝被析構,human_num=0 ,於是h2.print(),同樣輸出0,再h1,h2被析構,分別輸出-1,-2
human h2 = f1(h1);
h2.print();
return 0;
}