Loading [MathJax]/jax/output/CommonHTML/config.js
首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >【C++】类和对象之拷贝构造函数篇

【C++】类和对象之拷贝构造函数篇

作者头像
zxctscl
发布于 2024-02-25 02:05:47
发布于 2024-02-25 02:05:47
2620
举报
文章被收录于专栏:zxctscl个人专栏zxctscl个人专栏

个人主页zxctscl 文章封面来自:艺术家–贤海林 如有转载请先通知

1. 前言

在前面学习了6个默认成员函数中的构造函数和析构函数 【C++】构造函数和析构函数详解,接下来继续往后看拷贝构造函数。

拷贝构造函数就是用一个同类型的其他对象来构造。 要学习拷贝构造函数,得先了解传值传参和传引用传参。

2. 传值传参和传引用传参

代码语言:javascript
AI代码解释
复制
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	Date(Date& d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	// 内置类型
	int _year;
	int _month;
	int _day;
};
void func1(Date d)
{

}
void func2(Date& rd)
{

}
int main()
{
	Date d1(2024, 2, 24);
	func1(d1);
	func2(d1);

	return 0;
}

C++规定自定义类型都会调用拷贝构造。

所以func2(d1);rd是d1的别名,直接完成调用了,不存在再有一个函数来传值传参。

来看看不传引用会怎么样

代码语言:javascript
AI代码解释
复制
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}


	Date(Date d)
	{
		_year = d._year;
		_month = d._month;
		_day = d._day;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	
	int _year;
	int _month;
	int _day;
};

int main()
{
	Date d1(2024, 2, 24);
	Date d2(d1);
	return 0;
}

调用拷贝构造,要先传参,这里是传值,传参,会形成一个新的拷贝构造,进不来这个函数,一直递归下去。使用传值传参就不行。

3. 概念

在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎。

那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢? 拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

4. 特征

拷贝构造函数也是特殊的成员函数,其特征如下:

  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。

有时候可能会发生修改对象,为了保护对象,就可以在它前面加上const。 是一种权限的缩小。

像下面的场景就能被检查出来:

就只能这样写:

  1. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内置类型成员内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。

像下面的代码中就没有拷贝构造:

代码语言:javascript
AI代码解释
复制
class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	// 内置类型
	int _year;
	int _month;
	int _day;

	
};

int main()
{
	Date d1(2024, 2, 24);
	Date d2(d1);
	d1.Print();
	d2.Print();

	return 0;
}
代码语言:javascript
AI代码解释
复制
class Time
{
public:
	~Time()
	{
		cout << "~Time()" << endl;
	}

	// 强制编译器生成
	Time() = default;

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

private:
	int _hour;
	int _minute;
	int _second;
};

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}

	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}

private:
	// 内置类型
	int _year;
	int _month;
	int _day;

	//自定义类型
	Time _t;
	
};

int main()
{
	Date d1(2024, 2, 24);
	Date d2(d1);
	d1.Print();
	d2.Print();

	return 0;
}

在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定 义类型是调用其拷贝构造函数完成拷贝的。

  1. 编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?
代码语言:javascript
AI代码解释
复制
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
			return;
		}
		_size = 0;
		_capacity = capacity;
	}

	// Stack st2(st1);
	Stack(const Stack& s)
	{
		DataType* tmp = (DataType*)malloc(s._capacity *(sizeof(DataType)));
		if (tmp == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}

		memcpy(tmp, s._array, sizeof(DataType) * s._size);

		_array = tmp;
		_size = s._size;
		_capacity = s._capacity;
	}

	void Push(const DataType& data)
	{
		// CheckCapacity();
		_array[_size] = data;
		_size++;
	}

	~Stack()
	{
		if (_array)
		{
			free(_array);
			_array = nullptr;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	DataType* _array;
	size_t _size;
	size_t _capacity;
};


int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2(s1);
	return 0;
}

看这里s1和s2置空,s1置空不影响s2置空,他们是两个对象。但他们的地址指向同一个空间,同一个空间不能释放两次。会导致野指针。

注意:类中如果没有涉及资源申请时,拷贝构造函数是否写都可以;一旦涉及到资源申请时,则拷贝构造函数是一定要写的,否则就是浅拷贝。

  1. 拷贝构造函数典型调用场景: 使用已存在对象创建新对象 函数参数类型为类类型对象 函数返回值类型为类类型对象
代码语言:javascript
AI代码解释
复制
class Date
{
public:
	Date(int year, int minute, int day)
	{
		cout << "Date(int,int,int):" << this << endl;
	}
	Date(const Date& d)
	{
		cout << "Date(const Date& d):" << this << endl;
	}
	~Date()
	{
		cout << "~Date():" << this << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
Date Test(Date d)
{
	Date temp(d);
	return temp;
}
int main()
{
	Date d1(2022, 1, 13);
	Test(d1);
	return 0;
}

为了提高程序效率,一般对象传参时,尽量使用引用类型,返回时根据实际场景,能用引用尽量使用引用。

有问题请指出,大家一起进步!!!

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-02-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
编辑精选文章
换一批
【C++修行之道】类和对象(三)拷贝构造函数
四、编译器生成的默认拷贝构造函数已经可以完成字节序的值拷贝了,还需要自己显式实现吗?
走在努力路上的自己
2024/05/31
3050
【C++修行之道】类和对象(三)拷贝构造函数
【c++】类和对象(四)深入了解拷贝构造函数
拷贝构造函数是构造函数的一个重载形式,拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用,这个我们后面进行讲解
用户11029103
2024/04/02
2500
【c++】类和对象(四)深入了解拷贝构造函数
【C++】拷贝构造函数和赋值运算符重载详解
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存 在的类类型对象创建新对象时由编译器自动调用。 拷贝构造函数是一个特殊的构造函数,用于创建一个新的对象,其内容与另一个已存在的对象相同。在C++中,拷贝构造函数通常用于将一个对象的值复制到另一个对象中(一个对象存在,一个对象不存在),以便在程序中进行对象的赋值和传递操作时,能够确保对象的内容被正确复制。
P_M_P
2024/02/05
5500
【C++】拷贝构造函数和赋值运算符重载详解
C++奇迹之旅:深入思考拷贝构造函数
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
学习起来吧
2024/04/20
2060
C++奇迹之旅:深入思考拷贝构造函数
C++第四弹 -- 类与对象中篇上(构造函数 析构函数 拷贝构造函数)
让我们一起揭开 C++ 对象生命周期管理的神秘面纱,掌握构造函数、析构函数和拷贝构造函数的精髓!
用户11317877
2024/10/16
2670
C++第四弹 -- 类与对象中篇上(构造函数 析构函数 拷贝构造函数)
C++从入门到精通——类的6个默认成员函数之拷贝构造函数
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。
鲜于言悠
2024/04/16
6690
C++从入门到精通——类的6个默认成员函数之拷贝构造函数
【C++类和对象】拷贝构造与赋值运算符重载
拷贝构造函数:拷贝构造是指在创建一个新对象时,使用已存在的对象作为其初始值的构造函数。只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
大耳朵土土垚
2024/04/20
3720
【C++类和对象】拷贝构造与赋值运算符重载
【C++】踏上C++学习之旅(八):深入“类和对象“世界,掌握编程的黄金法则(三)(内含运算符重载和拷贝构造函数)
在之前的文章中,相信大家已经对"类"这个面向对象的语法以及一些基本的用法已经掌握了,那么在本文中将会带着大家继续解读,"类和对象"世界别致的风景——“拷贝构造函数"和"赋值运算符重载”。当然还有精彩的运算符重载语法讲解哦~
埋头编程
2024/11/21
3580
【C++】踏上C++学习之旅(八):深入“类和对象“世界,掌握编程的黄金法则(三)(内含运算符重载和拷贝构造函数)
C++进阶之路:何为拷贝构造函数,深入理解浅拷贝与深拷贝(类与对象_中篇)
拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。
Srlua
2024/05/26
7100
C++进阶之路:何为拷贝构造函数,深入理解浅拷贝与深拷贝(类与对象_中篇)
【C++】C++入门—初识构造函数 , 析构函数,拷贝构造函数,赋值运算符重载
如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗? 并不是 任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数 我们实现了,编译器就不会生成了
叫我龙翔
2024/02/19
3840
【C++】C++入门—初识构造函数 , 析构函数,拷贝构造函数,赋值运算符重载
《吃透 C++ 类和对象(中):拷贝构造函数与赋值运算符重载深度解析》
前言: 在上篇博客中我们学习了构造函数和析构函数这两个类中的默认成员函数,今天这篇博客我想继续为大家分享拷贝构造函数和赋值运算符重载。主要是先介绍特点再通过举例说明,所以举例中的代码注释是很重要的。
草莓熊Lotso
2025/10/29
1540
《吃透 C++ 类和对象(中):拷贝构造函数与赋值运算符重载深度解析》
C++类和对象(中)
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员 函数。
二肥是只大懒蓝猫
2023/03/30
1.6K0
C++类和对象(中)
【C++ 初阶路】--- 类和对象(下)
通过上文 类和对象(中) 构造函数的学习,我们知道一个对象是怎么来的,那一个对象又是怎么没呢的?
用户11029269
2024/07/01
2270
【C++ 初阶路】--- 类和对象(下)
《一篇拿下!C++:类和对象(中):拷贝构造与赋值运算符重载》
如果一个构造函数的第⼀个参数是自身类类型的引用,且任何额外的参数都有默认值,则此构造函数也叫做拷贝构造函数,也就是说拷贝构造是⼀个特殊的构造函数。
用户11915063
2025/11/20
2340
《一篇拿下!C++:类和对象(中):拷贝构造与赋值运算符重载》
C++的六大“天选之子“拷贝构造与与运算符重载
假设哦我们需要创建两个一模一样的对象A和B. 那我们可以先创建一个对象A,再通过将A作为参数,传给B进行初始化, 即一个自定义类型实例化出的对象(B)用另一个该类型实例化出的对象(A)进行初始化.
初阶牛
2023/10/14
3440
C++的六大“天选之子“拷贝构造与与运算符重载
C++心决之类和对象详解(中篇)(封装入门二阶)
对于 Date 类,可以通过 Init 公有方法给对象设置日期,但如果每次创建对象时都调用该方法设置
一枕眠秋雨
2024/04/25
2310
C++心决之类和对象详解(中篇)(封装入门二阶)
类和对象之六大基础函数
续接前文,C++的类和对象,是基于C语言结构体(struct)的优化和功能扩充,今天我们介绍的中的六大基本函数,这六位大爷对应着其C++编写者对于在C语言的结构体使用时常用功能的封装,例如:初始化、销毁等,对于使用者来说绝对是一大利器,但对于初学者来说,它细而繁多且看似没有逻辑的规则让人头脑捉急。
比特大冒险
2023/04/16
7160
类和对象之六大基础函数
【C++】类和对象(第二篇)
如果有时候不初始化直接用可能就会出现问题,但是有时候我们可能会忘记初始化,直接就对对象进行一些操作了。
YIN_尹
2024/01/23
2670
【C++】类和对象(第二篇)
[C++]类与对象中篇
类与对象中篇:: 1.类的6个默认成员函数 如果一个类中什么成员都没有,简称为空类。空类真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成6个默认成员函数。 默认成员函数: 用户没有显示
IT编程爱好者
2023/04/12
6250
[C++]类与对象中篇
C++:类与对象(2)
       在我们学习数据结构的时候,我们总是要在使用一个对象前进行初始化,这似乎已经成为了一件无法改变的事情,如以下的Data类
小陈在拼命
2024/02/28
2720
C++:类与对象(2)
推荐阅读
相关推荐
【C++修行之道】类和对象(三)拷贝构造函数
更多 >
领券
社区新版编辑器体验调研
诚挚邀请您参与本次调研,分享您的真实使用感受与建议。您的反馈至关重要,感谢您的支持与参与!
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
首页
学习
活动
专区
圈层
工具
MCP广场
首页
学习
活动
专区
圈层
工具
MCP广场