第十二章:默认复制构造函数和赋值运算符

默认复制函数

1、当把初始化一个对象的时候,用另一个已经存在的对象赋值。

比如String str2 = str1;其中str2为已经生成的对象。这个时候,编译器会把str1中的成员按值赋给str2中的每个成员。
如果对象成员中没有使用new来分配动态内存空间,则编译器自动生成的默认赋值函数,就可以正确实现,而不会出现错误。
但是如果对象成员中有new分配的动态内存空间,比如下面的这个类,str2中的指针str和str1中的指针str会指向同一个内存空间。
当str2执行析构函数时,释放了内存空间。这个时候也就是说str1的str指向的内存空间被释放了。所以就会出现错误。
这个情况还有三种方式也会:
String str2(str1);
String str2 = String(str1);
String *pstr = new String(str1);

2、当对象按值传递给函数形参的时候。

比如void callmey(String str2); callmey(str1);//这个时候会产生一个临时对象,将str1中的成员按值赋给临时对象的成员。和上面
的情况一样,都会出现错误。

3、函数返回对象的时候,因为这个时候会产生临时对象,所以会调用默认复制构造函数。


应该定义默认复制构造函数为:(实现深度复制)
//复制构造函数
StringBad::StringBad(const StringBad &s)
{
	num_strings++;
	len = s.len;
	str = new char[len + 1];
	strcpy(str, s.str);
	cout << "调用了复制构造函数\n";
}

赋值运算符

当用一个已经生成的对象,给另外一个已经生成的对象赋值时,会调用赋值运算符。复制的时候和调用复制构造函数一样,都是成员按值赋值。
如果涉及到new动态分配内存空间,就会出现错误。
比如:
String str1("yxk");
String str2;
str2 = str1;//这个时候会调用赋值运算符函数,将str1中各个成员按值赋给str2中的各个成员。如果也涉及到new分配的动态内存时,也会出现错误。
String str3("xiaokui");
str3 = str1;//将str1中的值赋给str3中的值。这个因为存在new分配的动态内存,所以在赋值运算符函数中应该首先释放str3中存在的动态内存空间,
再分配内存,将str1中的str指向的内存空间内容复制过来。也正是因为先释放自身的内存空间,所以不能将对象自身赋值给自身。


应该定义赋值运算符为:(实现深度复制)

//赋值运算符
StringBad & StringBad::operator=(const StringBad & st)
{
	//首先不能自身赋给自身
	if (&st == this)
		return *this;
	
	delete [] str;//因为是给对象赋值,所以应该删除以前的内存,再重新分配
	len = st.len;
	str = new char[len + 1];
	strcpy(str, st.str);
	printf("调用了赋值运算符\n");
	return *this;
}

下面是C++ Primer Plus 第十二章的第一个例子:

#include <iostream>
#ifndef STRINGBAD_H_
#define STRINGBAD_H_

class StringBad
{
private:
	char * str;
	int len;
	static int num_strings;
public:
	StringBad(const char *s);
	StringBad();
	~StringBad();
	StringBad(const StringBad &s);//复制构造函数
	StringBad & StringBad::operator=(const StringBad & st);//赋值运算符
	friend std::ostream & operator<<(std::ostream &os, const StringBad & st);
};
#endif

#include <cstring>
#include "StringBad.h"
using namespace std;

int StringBad::num_strings = 0;

StringBad::StringBad(const char *s)
{
	len = strlen(s);
	str = new char[len + 1];
	strcpy(str, s);
	num_strings++;
	cout << "*******************\n";
	cout << num_strings << ": " << str << endl;
	cout << "*******************\n";
}
StringBad::StringBad()
{
	len = 4;
	str = new char[4];
	strcpy(str, "C++");
	num_strings++;
	cout << "**************************************\n";
	cout << num_strings << ": " << str << " Created!" << endl;
	cout << "**************************************\n";
}
StringBad::~StringBad()
{
	--num_strings;
	cout << "**************************************\n";
	cout << num_strings << " left, " << str << " deleted!"<< endl;;
	cout << "**************************************\n";
	delete [] str;
}

std::ostream & operator<<(ostream &os, const StringBad & st)
{
	os << st.str;
	return os;
}
//复制构造函数
StringBad::StringBad(const StringBad &s)
{
	num_strings++;
	len = s.len;
	str = new char[len + 1];
	strcpy(str, s.str);
	cout << "调用了复制构造函数\n";
}
//赋值运算符
StringBad & StringBad::operator=(const StringBad & st)
{
	//首先不能自身赋给自身
	if (&st == this)
		return *this;
	
	delete [] str;//因为是给对象赋值,所以应该删除以前的内存,再重新分配
	len = st.len;
	str = new char[len + 1];
	strcpy(str, st.str);
	printf("调用了赋值运算符\n");
	return *this;
}

#include "StringBad.h"
#include <iostream>

using namespace std;

void callme1(StringBad &);
void callme2(StringBad);

int main()
{
	{
		//cout << "String...............\n";
		StringBad headline1("celery stalks");
		StringBad headline2("LEttuce prey");
		StringBad sports("Spinish Leaves");
		cout << "headline1: " << headline1 << endl;
		cout << "headline2: " << headline2 << endl;
		cout << "sports: " << sports << endl;

		callme1(headline1);
		cout << "headline1: " << headline1 << endl;
		callme2(headline2);
		cout << "headline2: " << headline2 << endl;
		StringBad sailor = sports;
		cout << "sailor: " << sailor << endl; 
		cout << "sports: " << sports << endl;

		StringBad knot;
		knot = headline1;
		cout << "knot: " << knot << endl;

	}

	getchar();
	//getchar();
	return 0;
}

void callme1(StringBad & rsb)
{
	cout << "passed by reference: " << rsb << endl;
}

void callme2(StringBad  sb)
{
	cout << "passed by value: " << sb << endl;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值