天天看点

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行调用了带参数的构造函数创建临时变量。

  如何避免临时变量的产生呢?可以使用引用传递代替值传递。这样就不会产生临时对象了。

继续阅读