天天看點

c/c++整理--靜态成員和臨時對象一、看代碼寫結果——c++靜态成員和臨時對象二、什麼是臨時對象?臨時對象在什麼情況下産生?

一、看代碼寫結果——c++靜态成員和臨時對象

#include <iostream>

using namespace std;

class human
{
public:
	human()
	{
		human_num++;
	}
	static int human_num;
	~human()
	{
		human_num--;
		print();
	}
	void print()
	{
		cout<<"human num is: "<<human_num<<endl;
	}
};

int human::human_num = 0;

human f1(human x)
{
	x.print();
	return x;
}

int main()
{
	human h1;
	h1.print();
	human h2 = f1(h1);
	h2.print();
	
	return 0;
}
           

解析:

  這個程式的human類有一個靜态成員human_num,每執行一次普通的構造函數human_num加1,每指向一次析構函數,human_num減1。注意,在f1()函數中會使用預設的複制構造函數,而預設的複制構造函數沒有對human_num處理。

  代碼第34行,隻構造了對象h1(調用普通構造函數),是以列印1。

  代碼第35行,使用值傳遞參數的方式調用了f1()函數,這裡分為3步;

  (1)在f1函數内首先會調用複制構造函數生成一個臨時對象,是以代碼第27行列印1。

  (2)f1函數内調用複制構造函數,給main的對象h2初始化(複制臨時對象)

  (3)f1函數傳回後,臨時對象發生析構,此時human的靜态成員human為0,列印出0。

  代碼第36行列印的還是0。

  main函數結束時有h1和h2兩個對象要發生析構,是以分别列印出-1和-2。

  程式的意圖很明顯,就是靜态成員用human_num記錄類human的執行個體數。然而,由于預設的複制構造函數沒有對靜态成員操作,導緻了執行結果的不正确。這裡可以通過添加一個自定義的複制構造函數解決。

human(human& h)
{
    human_num++;
}
           

此時human_num就能起到應有的作用了。

執行結果:

human num is: 1
human num is: 1
human num is: 0
human num is: 0
human num is: -1
human num is: -2
           

二、什麼是臨時對象?臨時對象在什麼情況下産生?

  當程式員之間進行交談時,經常把僅僅需要一小段時間的變量稱為臨時變量。例如在下面的swap函數裡:

void swap(int &a, int &b)
{
	int temp = a;
	a = b;
	b = temp;
}
           

  通常稱temp為臨時變量。但在c++裡,temp根本不是臨時變量。實際上,他隻是一個函數的局部變量。

  真正的臨時對象時看不見的,他不會出現在程式代碼中。大多數情況下,他會影響程式執行的效率,是以有時想避免臨時對象的産生。它通常在一下兩種情況下産生。

(1)參數按值傳遞。

(2)傳回值按值傳遞。

參考下面代碼:

#include <iostream>

using namespace std;

class Test
{
	int num;
public:
	Test() : num(0) { }						//預設構造函數
	Test(int number) : num(number) { }		//帶參數的構造函數
	void print()							//列印私有成員num
	{
		cout<<"num = "<<num<<endl;
	}
	~Test()
	{
		cout<<"destructor: this = "<<this<<",num = "<<num<<endl;
	}
};

Test fun1(Test test)						//參數按值傳遞
{
	test.print();
}

void fun2()									//傳回值按值傳遞
{
	Test t(3);
	return t;
}

int main()
{
	Test t1(1);
	fun1(t1);								//對象傳入
	fun1(2);								//整型數2傳入
	t1 = fun2();
	
	return 0;
}
           

  程式中fun1()參數是按值傳遞的,fun2函數的傳回值是按值傳遞的。在Test類的析構函數中列印了this指針的值,下面是執行結果:

num = 1
destructor: this = 0xbffb2b84,num = 1     (fun1内的臨時對象析構)
num = 2
destructor: this = 0xbffb2b88,num = 2     (fun1内的臨時對象析構)
destructor: this = 0xbffb2b8c,num = 3     (fun2内傳回的臨時對象析構)
destructor: this = 0xbffb2b80,num = 3     (main内的t1析構)
           

  這裡代碼第35,36行使用了兩種類型參數傳入fun1函數。它們都會生成臨時變量,不同點是采用不同的方式:第35行的調用使用了複制構造函數建立臨時變量,而第36行調用了帶參數的構造函數建立臨時變量。

  如何避免臨時變量的産生呢?可以使用引用傳遞代替值傳遞。這樣就不會産生臨時對象了。

繼續閱讀