C++“拷贝构造函数”和“重载 = 运算符”

本文详细介绍了C++中的拷贝构造函数,包括其功能、定义方法和特点,以及系统自动生成的缺省拷贝构造函数。同时,深入讨论了浅拷贝和深拷贝的概念,通过实例展示了未定义拷贝构造函数时可能出现的问题以及如何通过自定义拷贝构造函数实现深拷贝。此外,还简单提及了重载=运算符与拷贝构造函数的类比关系。
摘要由CSDN通过智能技术生成

一:拷贝构造函数和缺省拷贝构造函数

(一)拷贝构造函数

1.功能介绍

拷贝构造函数是一种特殊的构造函数,作用是用一个已知的对象来初始化一个新创建的同类的对象。
关键字:①新创建的;②同类的;

2.定义方法

ClassName::ClassName([const]ClassName & obj)  //注意形参是实参的【常】引用
	{
		<函数体>
	}

(如果是类体内进行定义,那么把类名限定去掉即可。)

3.特点

①只有一个参数,且形参必须是对实参的引用(实参的别名);
②如果给出关键字 const ,那么就代表实参受到保护,不能修改实参的数据;
③关键字const并不是一定要给出,但通常情况下都会用到关键字来限定;
④函数名与类名相同,并且没有返回值;
⑤每个类一定会有一个拷贝构造函数,若没有定义拷贝构造函数则代表函数自动生成一个缺省拷贝构造函数
⑥当给新的同类对象赋值时,系统自动调用此函数;

{
系统自动调用拷贝构造函数的情况:
①只有当产生新对象时;
②明确表示有一个对象初始化另一个对象;
③当对象作为函数参数时,系统处理成用实参对象初始化形参对象;
④当函数返回对象时,系统处理成用返回值对象初始化内存临时对象;
}

临时对象可参考博客: https://blog.csdn.net/JiajieZhuo/article/details/53889127

(二)缺省拷贝构造函数

1.功能

同拷贝构造函数一样,用来初始化一个新创建的同类的对象。
前提是编程者在定义类时没有定义拷贝构造函数

2.定义(系统自动生成)

class Point
{
	int x, y;
public:
	Point(int a = 0, int b = 0)
	{
		x = a;
		y = b;
	}
	~Point()
	{
		cout << x << "," << y << endl;
	}
};

例如:
上方代码段没有定义拷贝构造函数,那么系统自动生成缺省拷贝构造函数如下所示:

Point(const Point& p)
{
	x = p.x;
	y = p.y;
}

3.特点

①讲对象怕 p 的数据成员逐个赋值给新创建的对象的对应的数据成员;
②简单的数据拷贝;
③数据成员全部对应拷贝,不具有选择性;

(三)“浅”拷贝 和 “深”拷贝

1.“浅拷贝”

所谓“浅拷贝”就是指浅层的数据拷贝,典例就是系统自动生成的缺省拷贝构造函数。

2.“深”拷贝

当类的数据成员需要动态申请空间时,那么就需要编程者自己定义相应的拷贝构造函数,来实现“深”拷贝的功能。

3.范例

#include<iostream>
#include<cstring>
using namespace std;
class Student
{
	char* Name;
	int Age;
public:
	Student(char* namep, int age)
	{
		Age = age;
		if (namep)
		{
			Name = new char[strlen(namep) + 1];
			strcpy(Name, namep);
		}
		else
		{
			Name = NULL;
		}
	}
	~Student()
	{
		if (Name)
		{
			delete[] Name;
		}
	}
	void Show()
	{
		cout << Name << "," << Age << endl;
	}
};
int main()
{
	Student a("Csdn", 2022);
	Student b = a;     //......................................A行
	b.Show();
	return 0;
}
3.1. 没有定义拷贝构造函数

系统自动产生缺省拷贝构造函数,如下:

Student::Student(const Student& s)   //"浅"拷贝构造函数 
{
	Name = s.Name;    //注意,直接赋值地址 .........................B行
	Age = s.Age;    
}

此时的构造函数就是上述的“浅”拷贝(简单的数据拷贝)

注意看B行,数据仅仅是简单的数据拷贝,并没有实际动态申请空间,那么就意味着A行代码中的新定义的对象 b 中的 Name 数据成员和已知的对象 a 中的 Name 数据成员指向了同一个地址
该段代码在运行时输出了 “Csdn,2022” 后出错,原因正是 a.Name 和 b.Name 指向了同一个地址,这在程序赋值时看似没问题,但当程序调用析构函数时由于对象 a 和对象 b 的 Name 指向了同一段内存空间,意味着该空间会被释放两次,显然会报错。(系统首先撤销对象 b 的 Name 指针指向的内存空间,然后再撤销对象 a 的 Name 指针指向的内存空间,由于空间已经被撤销过一次,所以二次撤销时出错)

在这里插入图片描述

3.2.定义拷贝构造函数
Student::Student(const Student& s)  
{
	Age = s.Age;    
	Name = s.Name;    
	if(s.Name)
	{
		Name=new char[strlen(s,Name)+1];
		strcpy(Name,s.Name);
	}
	else
	{
		Name=NULL;
	}
	
}

此时,为对象 b 也动态申请了一个新的内存空间,那么在程序最后调用析构函数时分别释放对应的内存空间就不会出错了。

在这里插入图片描述

由此看出,假如没有动态申请空间,那么使用系统自动生成的“浅”拷贝构造函数就可以了。

二:重载 = 运算符(类比拷贝构造函数)

(一)一般概念

对于任意一个类,如果编程者没有显式定义赋值运算符重载函数,C++编译器会自动生成赋值运算符重载函数 operate= ,完成两个同类对象的直接赋值。
例如:
系统自动生成:

Student & Student::operate=(Student &p)
{
	Age=p.Age;
	Name=p.Name;
	return *this;    //*this是对象自身 
}

(二)特点

①只能使用成员函数实现;
②不能被派生类继承;
③不能定义成虚函数;
④若编程内没有显式定义赋值运算符重载函数,C++会自动生成;

(三)类比拷贝构造函数

“如果类中有指针指向动态分配的内存空间,编程者就必须定义赋值运算符重载函数。”相信读者类比之前的拷贝构造函数会明白其中的道理。为了留给大人想象空间,小的不再详细叙述。
(累了,第一次写博客,谅解)

写这篇博客的过程中我实在没了思路,在CSDN搜索了一下“拷贝构造函数”,发现“大佬终究是大佬”,这句话一点儿也不假。 附上我中间参考的一篇博客吧,给我看的明明白白的!!!https://blog.csdn.net/lwbeyond/article/details/6202256

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Duang~Lucky.Mr.Li

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值