【C++】拷贝构造函数和赋值函数

<span style="font-family:Microsoft YaHei;">#include <iostream>
using namespace std;

class String {
public:
	String() ;
	String(const String &other) ;
	~String() ;
	String & operator = (const String &other) ;
private:
	char *m_data;
	int val;
};</span>

位拷贝和值拷贝

构造函数、析构函数、赋值函数是每个类最基本的函数。每个类只有一个析构函数和一个赋值函数。但有很两个构造函数,一个为拷贝构造函数,其他为普通构造函数。

对于一个类,如果不编写这四个函数,C++编译器将自动为A产生四个默认函数。那么既然能自动生成函数,为什么还要自定义?原因之一是默认的拷贝构造函数和默认的赋值函数都采用的是位拷贝而非值拷贝。

位拷贝拷贝的是地址,值拷贝拷贝的是内容。

在上面定义的String类里,如果定义两个String的对象a和b。当利用位拷贝时,a = b,其中a.val = b.val; 这个没问题

但是a.m_data = b.m_data就错了,a.m_data 和b.m_data作为指针将指向同一个区域。这样出现问题:

1. a.m_data 原来的内存区域未释放,造成内存泄露

2. a.m_data和b.m_data指向同一块区域,任何一方改变将会影响到另一方

3. 当对象释放时,b.m_data会释放两次

因此

当类中含有指针变量时,默认拷贝构造函数和默认赋值函数由于使用位拷贝就隐含了错误,这时需要自己定义。

结论

1. 有一中特别常见的情况需要自己定义拷贝构造函数:类具有指针函数

2. 赋值操作符和拷贝构造函数可以看成一个单元,当需要其中一个时,我们几乎也肯定需要另一个

3. 三法则:如果类需要析构函数,则它也需要赋值操作符和拷贝构造函数

注意

1. 如果没有定义拷贝构造函数,编译器会自动生成默认的拷贝构造函数

2. 如果定义了其他构造函数,包括拷贝构造函数,编译器绝不会生成默认构造函数

3. 即使自己写了析构函数,编译器也会自动生成默认析构函数

拷贝构造函数 VS 赋值函数

/*
 * copy.cpp
 *
 *  Created on: 2015?8?5?
 *      Author: nanzhou
 */
#include <iostream>
using namespace std;

class String {
public:
	String(const char *str) ;
	String(const String &other) ;
	~String() ;
	String & operator = (const String &other) ;
private:
	char *m_data;
};

String::String(const char *str) {
	cout << "zidingyi Constructor" << endl;
	if (NULL == str) {
		m_data = new char[1];
		*m_data = '\0';
	}
	else {
		int length = strlen(str);
		m_data = new char[length + 1];
		strcpy(m_data, str);
	}
}

String::String(const String &other) {
	cout << "zidingyi Copy Constructor" << endl;
	int length = strlen(other.m_data);
	m_data = new char[length + 1];
	strcpy(m_data, other.m_data);
}

String & String::operator = (const String &other) {
	cout << "zidingyi fuzhi function" << endl;
	if ( this == &other) {
		return *this;
	}
	else {
		delete [] m_data;
		int length = strlen(other.m_data);
		m_data = new char[lenght + 1];
		strcpy (m_data, other.m_data);
		return *this;
	}
}

String::~String() {
	cout << "zidingyi xigou function" << endl;
	delete [] m_data;
}

int main() {
	cout << "a(\"abc\")" << endl;
	String a("abc");

	cout << "b(\"cde\")" << endl;
	String b("cde");

	cout << " d = a " << endl;
	String d = a;

	cout << "c = a" << endl;
	String c(b);

	cout << " c = a " << endl;
	c = a;

	cout<<endl;
}


1. 赋值函数中,上来比较this == &other是很必要的,要防止自身复制,这是很危险的,因为下面有delete []m_data,如果提前把m_data释放了,指针就成了野指针,再赋值就错了。
2. 赋值函数里,紧接着就要释放m_data,否则就没机会了,下边就有新指向了
3. 拷贝构造函数是在对象被创建时调用,赋值函数只能被已经存在了的对象调用
String c = a;调用拷贝构造函数,因为c一开始不存在,最好携程String c(a);

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
拷贝构造函数是用来创建一个新对象并将其初始化为给定对象的副本的特殊成员函数。它通常用于以下情况: - 当一个对象通过值传递给函数或以值的形式返回时 - 当一个对象用另一个对象进行初始化时 - 当一个对象作为另一个对象的成员进行初始化时 对于类`Person`的拷贝构造函数,它会接受一个`const Person&`类型的参数,并将其成员变量`name_`赋值给新创建的对象的`name_`成员变量。 赋值运算符是用于将一个对象的值分配给另一个已经存在的对象的成员函数。它通常用于以下情况: - 当一个对象被另一个对象赋值时 - 当一个对象作为另一个对象的成员进行赋值时 对于类`Person`的赋值运算符,它会接受一个`const Person&`类型的参数,并将其成员变量`name_`赋值给当前对象的`name_`成员变量。然后,它将返回一个指向左侧运算对象的引用,以支持连续赋值的操作。 如果在类定义中没有显式定义拷贝构造函数赋值运算符,编译器会为类生成默认拷贝构造函数赋值运算符。此外,我们还可以使用`=default`来显式要求编译器生成合成的拷贝构造函数赋值运算符。这将使用默认的实现来完成拷贝和赋值操作。 总之,拷贝构造函数用于创建一个对象的副本,而赋值运算符用于将一个对象的值赋给另一个已经存在的对象。<span class="em">1</span><span class="em">2</span><span class="em">3</span> #### 引用[.reference_title] - *1* *2* *3* [C++拷贝构造函数与拷贝赋值运算符](https://blog.csdn.net/xiongya8888/article/details/89424224)[target="_blank" data-report-click={"spm":"1018.2226.3001.9630","extra":{"utm_source":"vip_chatgpt_common_search_pc_result","utm_medium":"distribute.pc_search_result.none-task-cask-2~all~insert_cask~default-1-null.142^v93^chatsearchT3_2"}}] [.reference_item style="max-width: 100%"] [ .reference_list ]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值