第十二章:默認複製構造函數和賦值運算符

默認複製函數

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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章