C++深拷贝构造函数的运用

深拷贝和浅拷贝的区别

拷贝构造函数是用于将一个对象复制到新创建的对象中。
浅拷贝只是复制了对象的引用地址,两个对象指向同一个内存地址,所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝
深拷贝是将对象及值复制过来,两个对象修改其中任意的值另一个值不会改变,这就是深拷贝

说明

C++类中存在默认的隐式拷贝构造函数,每当程序生成了对象副本时,编译器都将使用复制构造函数。这种默认的隐式构造函数是按值进行复制的,也就是说这种隐式拷贝构造函数为浅拷贝构造函数。

下面代码举例:

#include <iostream>
using namespace std;

class test{
public:
	test(const char* str){
		a = strlen(str);//改为sizeof就是错的
		newStr = new char[a + 1];
		strcpy(newStr, str);
		g += 1;
		cout << "第" << g << "次调用:";
		cout <<"test构造测试:" << newStr << endl;
	}
	~test(){
		x += 1;
		cout << "第" << x << "次调用:";
		cout << "test析构测试:"<< newStr << endl;
		delete [] newStr;
		newStr = nullptr;
	}
	friend ostream& operator<<(ostream &out, const test& t){
		out << t.newStr << endl;
		return out;
	}
	char* retStr()const{
		return newStr;
	}
private:
	int a;
	char* newStr;
	static int g; //计算调用几次构造函数
	static int x;//计算调用几次析构函数
};
int test::g = 0;
int test::x = 0;


 void callStr(test ts){	
 	cout << "String  value:\n";
 	cout <<"callStr函数:"<< ts.retStr() << endl;
 }
 
    
  int main(){
  	test t1("aaaaaaa1");
  	test t2("bbbbbbb2");
  	callStr(t1);
  	test t3 = "ccccccc3";
  	return 0;
   }

在这里插入图片描述
这里可以发现构造函数调用了3次,析构函数却调用了4次,且第4次构造函数是乱码。
在调用callStr(test ts)函数时,test类创建一个临时变量ts通过C++默认的拷贝构造函数来获取t1的值(函数结束就释放,调用一次析构函数),这里并没有调用我创建的构造函数,所以构造函数会比析构函数少一次。
因为是浅拷贝,是通过值进行传递。等同如下:
ts.str = t1.str;
ts与t1两个指向同一个地址的字符串,当函数callStr结束时,ts也会被释放,自动的调用析构函数。又由于t1创建字符串的空间被释放了,所以t1类结束时没有办法在进行释放空间,最后会有乱码产生。

解决方案

不使用C++默认的拷贝构造函数,定义一个深拷贝构造函数来进行,在类中定义如下:

test(const test& str){
	g += 1;
	newStr = new char[a + 1];
	strcpy(newStr, str.retStr());
	cout << "第" << g << "次调用:";
	cout << "test构造测试:" << newStr << endl;
}

在这里插入图片描述

总结

当类中包含了使用new初始化的指针成员时,应当定义一个深拷贝构造函数,来复制指向的数据,而不是指针。

  • 3
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
C++中的拷贝构造函数是用于创建一个新对象并复制另一个对象的所有成员变量的构造函数。它通常用于创建对象的副本,确保两个对象在内存中是完全独立的。 下面是一个示例代码,展示了如何实现拷贝构造函数: ```cpp #include <iostream> #include <cstring> class MyClass { public: int* data; // 默认构造函数 MyClass() { data = new int; *data = 0; } // 拷贝构造函数 MyClass(const MyClass& other) { data = new int; *data = *other.data; } // 析构函数 ~MyClass() { delete data; } }; int main() { // 创建对象 obj1 MyClass obj1; std::cout << "obj1.data: " << *obj1.data << std::endl; // 使用拷贝构造函数创建对象 obj2,并将 obj1 的值复制给 obj2 MyClass obj2(obj1); std::cout << "obj2.data: " << *obj2.data << std::endl; // 修改 obj2 的值 *obj2.data = 10; // 验证 obj1 和 obj2 的值是否相互独立 std::cout << "obj1.data: " << *obj1.data << std::endl; // 0 std::cout << "obj2.data: " << *obj2.data << std::endl; // 10 return 0; } ``` 在上面的示例中,我们定义了一个名为 `MyClass` 的类,其中包含一个成员变量 `data`,它是一个指向 int 类型的指针。我们通过拷贝构造函数,使用 `new` 操作符为 `data` 成员变量分配了内存,并将源对象的值复制到新对象中。 需要注意的是,在拷贝构造函数中,我们需要手动分配内存,并将源对象的数据复制到新分配的内存中。这样可以确保新对象和源对象具有相同的值,但是它们在内存中是独立的。 希望以上解答能对你有所帮助!如有更多问题,请继续提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值