C++_复习03(拷贝构造函数的三种调用场景)

一、拷贝构造函数的定义及作用

拷贝构造函数是一种特殊的构造函数,函数的名称必须和类名称一致,它必须的一个参数是本类型的一个引用变量

拷贝函数用于对象的初始化。 例:一个简单得拷贝函数如下

class Test3{
public:
	Test3(const Test3&obj) {
		a = obj.a + 100;
		b = obj.b + 100;
		cout << "拷贝构造函数" << endl;
	}
	~Test3(){//析构函数 
	}
};

 二、拷贝构造函数的三种调用场景

2.1 对象通过另外一个对象进行初始化

直接定义一个对象来初始化另一个对象,具体有两种写法。

class Test3{
public:
	Test3(const Test3&obj) {
		a = obj.a + 100;
		b = obj.b + 100;
		cout << "拷贝构造函数" << endl;
	}
	~Test3(){//析构函数 
	}
};
void objectplay1()
{
	//赋值构造函数:用一个对象初始化另外一个对象
	Test3 t1(1, 2); //这里实际上只传入了2,逗号表达式传入最后一个值!!
	//第一种调用方法
		//注意赋值操作:t2=t1 不会调用拷贝构造函数
		//相当于复制操作及可以理解为操作符重载
	Test3 t2 = t1; //用t1来初始化t2

	//第二种调用方法
	Test3 t3(t2); //括号法初始化
}

 2.2 对象以值传递的方式传入函数参数

该场景中有一个全局函数 void f(Location p), void f(Location p)的传入参数是一个元素,就是我们定义的Location。

class Location {
public:
	Location(int _x, int _y) {
		x = _x;
		y = _y;
	}
	Location(Location &obj) {
		x = obj.x + 10;
		y = obj.y + 10;
	}
	~Location() {
		cout << "an object destroyed." << endl;
	}
	int GexX() { return x; } int GetY() { return y; }
private:
	int x;
	int y;
};


//形参是一个元素,此时初始化会调用一次拷贝构造函数!!!
void f(Location p) {
	cout << p.GexX() << endl;
}

void objectplay2() {
	Location b(1, 2);
	f(b);// b实参取值初始化形参P的过程当中会调用拷贝构造函数!!!!
}

调用f()函数的过程中,会经历一下几个步骤:

  • 当使用 void f(Location p) 的时候,会产生一个匿名对象,假定匿名对象为xx。
  • 调用拷贝构造函数去初始化匿名对象。【类似:Location xx(p);】
  • 等 void f(Location p)函数执行完毕后,就会析构掉这个匿名对象。

可以通过分步调试验证!

2.3 对象以值传递的方式从函数返回

该场景中我们定义了一个 Location g() ,返回值为我们的对象。

class Location {
public:
	Location(int _x, int _y) {
		x = _x;
		y = _y;
	}
	Location(Location &obj) {
		x = obj.x + 10;
		y = obj.y + 10;
	}
	~Location() {
		cout << "an object destroyed." << endl;
	}
	int GexX() { return x; } int GetY() { return y; }
private:
	int x;
	int y;
};

//第三种 难点
//g函数返回一个元素
//结论1:函数的返回值是一个元素(复杂类型的),返回的是一个新的匿名对象
    //所以会调用匿名对象的拷贝构造函数!
//结论2:匿名对象的去和留
	//如果用匿名对象初始化宁外一个同类型的对象,那么匿名对象直接转成有名对象
	//如果用匿名对象赋值(=)给宁外一个同类型的对象,匿名对象就被析构。
//你这样写C++设计者就认为你要返回一个新对象(匿名对象)
Location g() {
	Location a(4, 5);
	//这个时候会执行一次拷贝构造函数!
	return a; 
	//紧接着他析构了一个构造函数
}

void objectplay3_1()
{
	//又析构了,析构的是匿名对象
	g();
}

void objectplay3_2()
{
	//把匿名对象直接初始化为m
	//此时C++编译器直接把匿名对象变成m,匿名函数没被析构直接变为m,没有调用拷贝构造函数
	//Location m = g(); //似乎已经被优化,这样写的话编译不通过
	Location m2(1,2);
	m2 = g();//因为匿名对象是=给m2,匿名对象被析构

}

在void objectplay3_1场景中执行到Location g() 的return时,会产生以下几个重要的步骤:

  • 首先会产生一个匿名对象,假定匿名对象为xx
  • 然后调用拷贝构造函数把a的值给匿名函数【类似:Location xx(a);】
  • 等Location g()执行完后,就析构掉匿名对象

在void objectplay3_2场景中执行到Location g() 的return时,会产生以下几个重要的步骤:

  • 首先会产生一个匿名对象,假定匿名对象为xx
  • 然后调用拷贝构造函数把a的值给匿名函数【类似:Location xx(a);】
  • 匿名对象赋值给m2,所以析构掉匿名对象
发布了27 篇原创文章 · 获赞 3 · 访问量 3341

猜你喜欢

转载自blog.csdn.net/weixin_40977054/article/details/102455660