0902C++析构和构造函数基础2

1.1拷贝构造函数调用时机

概述:
C++中拷贝构造函数调用时机通常有三种情况

  • 使用一个已经创建完毕的对象来初始化一个新对象
  • 值传递的方式给函数参数传值
  • 以值方式返回局部对象

1. 使用一个已经创建完毕的对象来初始化一个新对象

#include<iostream>
#include<string>
using namespace std;
class h_idol
{
public:
	//构造函数
	h_idol() {
		idol = "何运晨"; 
		cout << "调用无参构造函数!" <<  endl;
	}
    h_idol(string a) {
		idol = a;
		cout << "调用有参构造函数!" <<  endl;
	}
	//(3)拷贝构造函数
	h_idol(const h_idol& a) {
		idol = a.idol;
		cout << "调用拷贝构造函数!" << endl;
	}

//析构函数
	~h_idol()
	{
		cout << "调用了h_idol的析构函数" << endl;
	}
public:
	string idol;
};
void call_idol_1() {
	h_idol idol02("道枝骏佑");//创建有参构造函数
	h_idol idol03(idol02); //调用拷贝构造函数
	h_idol idol04;
	cout<< idol04.idol << endl;
	idol04 = idol02;//不是调用拷贝构造函数,赋值操作
	cout<< idol03.idol << endl;	
}
int main() 
{
	call_idol_1();
	system("pause");
	return 0;
}
}

输出:

调用有参构造函数!
调用拷贝构造函数!
调用无参构造函数!
何运晨
道枝骏佑
调用了h_idol的析构函数
调用了h_idol的析构函数
调用了h_idol的析构函数
请按任意键继续. . .

2. 值传递的方式给函数参数传值

** 本质:**就是拷贝一个临时的副本出来,也就是调用拷贝构造函数来创建一个新的东西。

void change_idol(h_idol idol00)
 {
    idol01.idol = string("道枝骏佑"); 
    cout << idol00.idol << endl;
 }
void call_idol_1() {
	h_idol idol01; //无参构造函数
	change_idol(idol01);//实参传递给形参,这时候会调用拷贝构造函数,值传递只会拷贝出一个临时的副本,并不会影响下面的数据
	cout << idol01.idol << endl;

输出:

调用无参构造函数!
调用拷贝构造函数!
道枝骏佑
调用了h_idol的析构函数
何运晨     //没有影响idol01的数据
调用了h_idol的析构函数
请按任意键继续. . .

3. 以值方式返回局部对象(存在争议)

h_idol change_idol()
 {
    h_idol idol00;
    cout << (int *)&idol00 << endl;
	cout << idol00.idol << endl;
	return idol00; //局部对象有个特点,函数执行完之后就会被释放掉,返回的时候,它会根据diol00,创建一个新的对象然后返idol01回到外面的对象,故它返回的不是idol00。
 }
void call_idol_1() {
	h_idol idol01 = change_idol();
	cout << (int *)&idol01 << endl;	
	cout << idol01.idol << endl;
}

输出:

调用无参构造函数!
0x6dfe6c
何运晨
0x6dfe6c
何运晨
调用了h_idol的析构函数
请按任意键继续. . .

1.2 构造函数调用规则

概述:

  1. 默认情况下,c++编译器至少给一个类上述添加3个构造函数
  2. 如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造
  3. 如果用户定义拷贝构造函数,c++不会再提供其他构造函数

1.如果用户定义有参构造函数,c++不在提供默认无参构造,但是会提供默认拷贝构造

class h_idol
{
public:
	//构造函数
//	h_idol() {
//		cout << "调用无参构造函数!" <<  endl;
//	}
    h_idol(string a) {
		idol = a;
		cout << "调用有参构造函数!" <<  endl;
	}
	//(3)拷贝构造函数
//	h_idol(const h_idol& a) {
//		idol = a.idol;
//		cout << "调用拷贝构造函数!" << endl;
//	}

//析构函数
	~h_idol()
	{
		cout << "调用了h_idol的析构函数" << endl;
	}
public:
	string idol;
};
void call_idol_1() {
    //h_idol idol00;//错误提示:[Error] no matching function for call to 'h_idol::h_idol()'
	h_idol idol01("何运晨"); //用户提供的有参
	cout << idol01.idol << endl;
	h_idol idol02(idol01);//此时如果用户没有提供拷贝构造,编译器会提供
	cout << idol02.idol << endl; 
}

输出:

调用有参构造函数!
何运晨
调用拷贝构造函数!
何运晨
调用了h_idol的析构函数
调用了h_idol的析构函数
请按任意键继续. . .

2.如果用户定义拷贝构造函数,c++不会再提供其他构造函数

  • 如果用户自己没有提供默认构造,而调用了会出错
  • 时如果用户自己没有提供有参,而调用了会出错
class h_idol
{
public:
	//构造函数
//	h_idol() {
//		cout << "调用无参构造函数!" <<  endl;
//	}
//    h_idol(string a) {
//		idol = a;
//		cout << "调用有参构造函数!" <<  endl;
//}
//(3)拷贝构造函数
	h_idol(const h_idol& a) {
		idol = a.idol;
		cout << "调用拷贝构造函数!" << endl;
	}

//析构函数
	~h_idol()
	{
		cout << "调用了h_idol的析构函数" << endl;
	}
public:
	string idol;
};
	//调用无参构造函数
//h_idol change_idol()
// {
//    h_idol idol00;
//    cout << (int *)&idol00 << endl;
//	cout << idol00.idol << endl;
//	return idol00; 
// }
void call_idol_1() {
	h_idol idol00;//[Error] no matching function for call to 'h_idol::h_idol()'
	h_idol idol01("何运晨");//[Error] no matching function for call to 'h_idol::h_idol(const char [7])'
}

1.2深拷贝和浅拷贝

  • 浅拷贝:简单的赋值拷贝操作
  • 深拷贝:在堆区重新申请空间,进行拷贝操作
#include<iostream>
#include<string>
using namespace std;

class h_idol
{
public:
	//构造函数
	h_idol() {
		cout << "调用无参构造函数!" <<  endl;
	}
    h_idol(string a,double height) {
		idol = a;
		idol_height = new double(height);//把height创建在堆区,堆区的数据由程序员手动开辟和释放
		cout << "调用有参构造函数!" <<  endl;
}
//(3)拷贝构造函数
	h_idol(const h_idol& a) {
		idol = a.idol;
		//idol_height = a.idol_height 编译器就默认实现这行代码
		idol_height = new double(*a.idol_height);
		cout << "调用拷贝构造函数!" << endl;
	}

//析构函数
	~h_idol()
	{	
	//析构代码,将堆区开辟的数据做释放操作
	    cout << "调用了h_idol的析构函数" << endl;	
		if(idol_height != NULL){
			delete idol_height;
			idol_height = NULL;
		}
	}
public:
	string idol;
	double * idol_height;
};

void call_idol_1() {
	h_idol idol01("何运晨",1.85);
	cout << "idol01身高:" << *idol01.idol_height << endl;
	h_idol idol02(idol01);//idol01和idol02是栈区,先进后出,
	//idol02先被释放,结果导致堆区的区域重复被释放
	cout << "idol02身高:" << *idol02.idol_height << endl;
}
int main() 
{
	call_idol_1();
	system("pause");
	return 0;
}


输出:

调用有参构造函数!
idol01身高:1.85
调用拷贝构造函数!
idol02身高:1.85
调用了h_idol的析构函数
调用了h_idol的析构函数
请按任意键继续. . .

总结:如果属性有在堆区开辟的,一定要自己提供拷贝构造函数,防止浅拷贝带来的问题

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值