当前位置: 首页 > news >正文

c++拷贝构造函数(深浅拷贝)+运算符重载

1拷贝构造函数

1.1定义

只有一个形参,且该形参是对本类类型对象的引用(一般用const 修饰),在用已经存在的类类型对象穿件新对象是由编译器自动调用。(是一种特殊构造,即初始化一个一模一样的新对象)

1.2特征

  • 拷贝构造函数是一种特殊成员函数,是构造函数的一个重载形式
  • 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用
class Date 
{
public:
	Date(int year = 2004, int month = 10, int day = 1)//全缺省构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)//拷贝构造函数,这里必须是引用
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	Date d1;
	Date d2(d1);
	return 0;
}
  • 若为显式定义,编译器会生成默认的拷贝构造函数。默认拷贝构造函数对象按内存存储按字节序完成拷贝,这种方式成为浅拷贝或者值拷贝

简要介绍一下深拷贝和浅拷贝

浅拷贝/值拷贝:按字节拷贝,在复制对象时,仅复制对象的成员变量的值。若对象包含指针成员,那么浅拷贝只会复制指针的值,也就是复制后的对象和原对象的指针会指向同一块内存地址。这就意味着两个对象会共享同一块动态分配的内存。当其中一个对象被销毁时,它所指向的内存也会被释放,而另一个对象的指针就会变成悬空指针,这可能会引发程序崩溃或其他未定义行为。

深拷贝:在复制对象时,不仅会复制对象的成员变量的值,还会为指针成员分配新的内存空间,并将原对象指针所指向的内存中的数据复制到新分配的内存中。这样,复制后的对象和原对象就会拥有各自独立的内存空间,彼此之间不会相互影响。(开一样的空间,拷贝一份一模一样的东西)

像Date,My Queue等不需要显示拷贝构造,因为他是浅拷贝的类

像Stack需要显示拷贝构造,因为他是深拷贝的类

class Time
{
public:
	Time()
	{
		_hour = 1;
		_minute = 1;
		_second = 1;
	}
	Time(const Time& t)
	{
		_hour = t._hour;
		_minute = t._minute;
		_second = t._second;
		cout << "Time::Time(const Time&)" << endl;
	}

private:
	int _hour;
	int _minute;
	int _second;
};
class Date
{
private:
	//内置类型
	int _year;
	int _month;
	int _day;//编译器在拷贝时,完成字节序的值拷贝

	//自定义类型
	Time _t;//编译器在拷贝时,调用其构造函数完成拷贝
};
int main()
{
	Date d1;
	//这里是用已经创建好的d1拷贝构造d2,此处会调用Date类的拷贝构造函数
	//但是Date没有显式的拷贝构造函数,因此编译器会生成默认的拷贝构造函数
	Date d2(d1);
	Date d3 = d1;//这个和上一行作用一样
	
	return 0;
}

小结:

1.当类中包含动态分配的资源(像动态数组、动态对象等)时,为了防止多个对象共享同一块内存而引发问题(如悬空指针、重复释放内存),需要实现深拷贝。这就意味着在非默认拷贝构造函数里,要为新对象分配新的内存空间,再把原对象的数据复制到新的内存中。

2.如果没有管理资源,一般情况下不需要写拷贝构造函数,直接用默认的拷贝构造,如Date类

3.如果都是自定义类型成员,内置类型成员没有指向资源,也类似默认生成的拷贝构造函数就可以,如My Queue类

4.一般情况下,不需要显式析构函数的,就不需要写拷贝构造

2赋值运算符重载

2.1运算符重载

本质:运算符重载是具有特殊函数名的函数,也具有返回值类型,函数名字以及参数列表

目的:增强代码的可读性,

函数名字:关键字 operator后面接需要重载的运算符符号

函数原型:返回值类型 operator操作符(参数列表)

                 返回值类型主要取决于操作符到底干什么事,比如操作符是比较大小,返回值类型就是bool类型,如果是自增,则返回值就是原类(eg:Date类)

注意:

  • 重载操作符必须有一个类类型参数
  • 用于内置类型的操作符,其含义不可以改变,例如:+,-,*,.....
  • .*  ::  sizeof  ?:  .  以上5个运算符不能重载(笔试常考)
  • 作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐藏的this

如上图画波浪线的报错可知:如果我们重载运算符为全局,那么则无法访问私有成员,解决方法有以下三种:1.提供这些成员get和set方法;2.友元;3.重载成员函数(C++中常用这种)

2.2赋值运算符重载

1.赋值运算符重载格式

  • 参数类型:const& T(传递引用可以提高传参效率)
  • 返回值类型:T&,(返回引用可以提高返回的效率,有返回值目的是为了支持连续赋值)
  • 检测是否自己给自己赋值(存疑)
  • 返回*this:要符合连续赋值的含义
class Date {
public:
	Date(int year = 2004, int month = 10, int day = 20)//全缺省构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)//拷贝构造函数
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}
	Date& operator=(const Date& d)
	{
		//这里的this指针指代函数运行时调用该函数的对象  
		if (this != &d)//这一段代码是为了防止出现d1=d1;即自己给自己赋值的情况
		{
			_year = d._year;
			_month = d._month;
			_day = d._day;
		}
		return *this; 
	}
private:
	int _year;
	int _month;
	int _day;
};

区别拷贝构造和复制拷贝

int main()
{
	Date d1(2024, 04, 20);
	Date d2(d1);
	Date d3 = d1;//d2,d3都是拷贝构造,意思是创建两个与d1一样的实例化对象
	//注意,拷贝构造的本质是构造,构造同类型的对象,并且使之初始化为与d1一摸一样的对象
	//一个已经存在的对象,拷贝给另一个要创建的初始化的对象
	Date d4(2024, 05, 21);
	d1 = d4;//注意,这里不是拷贝构造,因为d1和d4都是已经存在的对象,
	//这里的本质是把一个已经存在的对象,拷贝给另一个已经存在的对象
    //d4相当于d,d1相当于this(见上个代码块)
	return 0;
}

2.赋值运算符只能重载成类的成员函数(不论形参的类型是什么),不能重载成全局函数

相关文章:

  • python 语言 设计模式
  • FRP的proxies只是建立通道,相当于建立与服务器沟通的不同通道而不是直接将路由器与服务器云端沟通
  • 深度学习-156-RAG技术之在ubuntu中的安装部署RAGFlow和简单应用
  • 嵌入式---烧录器
  • Vue客服组件集成Dify智能问答:从设计到落地(3)
  • 24.OpenCV中的霍夫直线检测
  • 紧跟政策步伐:道路运输安全员证报名指南​
  • 声学测温度原理解释
  • NeuroImage:膝关节炎如何影响大脑?静态与动态功能网络变化全解析
  • wx213基于php+vue+uniapp的新闻资讯小程序
  • 2025年的Android NDK 快速开发入门
  • cgroups
  • SVMSPro分布式综合安防管理平台--地图赋能智慧指挥调度新高度
  • Linux 线程:从零构建多线程应用:系统化解析线程API与底层设计逻辑
  • 人物4_Japanese
  • ubuntu20.04+qt5.12.8安装serialbus
  • 【Pandas】pandas DataFrame iat
  • 蓝桥杯篇---客观题
  • 学习笔记五——Rust 控制流全解析
  • 【Pandas】pandas DataFrame at
  • 云南省住房和城乡建设厅官方网站/2021年重大新闻事件
  • 做平面设计一般上哪个网站参考/网店运营与管理
  • mindmanager网站建设流程图/百度搜索关键词查询
  • 山西+网站建设/广告公司品牌营销推广
  • 电子商务网站分析/2022最新国际新闻10条简短
  • 制作网站详细步骤/企业营销型网站建设