C++的六大“天选之子“拷贝构造与与运算符重载

这篇具有很好参考价值的文章主要介绍了C++的六大“天选之子“拷贝构造与与运算符重载。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法

🎈个人主页:🎈 :✨✨✨初阶牛✨✨✨
🐻推荐专栏1: 🍔🍟🌯C语言初阶
🐻推荐专栏2: 🍔🍟🌯C语言进阶
🔑个人信条: 🌵知行合一
🍉本篇简介:>:讲解C++中有关类和对象的介绍,本篇是中篇的第结尾篇文章,讲解拷贝构造,运算符重载以及取地址重载符.
金句分享:
✨别在最好的年纪,辜负了最好的自己.✨

一、“拷贝构造函数”

拷贝构造函数

只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调用。

2.1 自动生成的"拷贝构造函数"

假设哦我们需要创建两个一模一样的对象AB.
C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法
那我们可以先创建一个对象A,再通过将A作为参数,传给B进行初始化,
即一个自定义类型实例化出的对象(B)用另一个该类型实例化出的对象(A)进行初始化.

class Date
{
public:

	Date(int year = 2020, 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 A(2023, 7, 20);
	A.Print();
	printf("\n");
	Date B(A);//会调用系统生成的拷贝构造
	B.Print();
	return 0;
}

运行结果:

2023-7-20

2023-7-20

其实拷贝构造函数就是构造函数的一种重载形式,他也是六大天选之子之一,没有显式定义时,编译器也会自动生成,但是只会完成"浅拷贝"(下面讲)…

2.2 自定义"拷贝构造函数"

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

class Date
{
public:

	Date(int year = 2020, int month = 1, int day = 1)//全缺省构造函数
	{
		_year = year;
		_month = month;
		_day = day;
	}
	Date(const Date& d)//拷贝构造函数
	{
		cout << "拷贝构造" << endl;
		_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(2023, 7, 20);
	d1.Print();
	printf("\n");
	Date d2(d1);
	d2.Print();
	return 0;
}

我们发现Date(const Date& d)这里使用了引用传参,如果直接传参会怎样呢?
C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法
为什么会报错呢?

void test(int a)
{

}

void test(Date d1)
{

}

int main()
{
	Date d1(2023, 7, 20);
	test(2);
	test(d1);
	return 0;
}

这段代码会调用Date 类的拷贝构造.
C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法
对于自定义类型作为参数时,必须调用该类型的拷贝构造函数.
所以可以回答上面的问题了.

C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法
所以拷贝构造函数传参时采用引用传参,这样就避免了传参时调用拷贝构造.

2.3 深浅拷贝?

前面在介绍编译器自动生成的"拷贝构造函数"时,提到了浅拷贝,那什么是浅拷贝呢?

浅拷贝:按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝
C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法

深拷贝:
C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法

示例:
栈类中没有显式定义拷贝构造函数,编译器自动生成的拷贝构造是浅拷贝带来的问题.

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

typedef int DataType;
class Stack
{
public:
	Stack(int capacity=5)//全缺省构造函数
	{
		cout << "Stack" << endl;
		_array = (DataType*)malloc(sizeof(DataType) * capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		_capacity = capacity;
		_size = 0;
	}
	void Push(DataType data)//压栈操作
	{
		CheckCapacity();
		_array[_size] = data;
		_size++;
	}
	~Stack()//析构函数
	{
		cout << "~Stack"<< endl;
		if (_array)
		{
			free(_array);
			_array = NULL;
			_capacity = 0;
			_size = 0;
		}
	}
private:
	void CheckCapacity()
	{
		if (_size == _capacity)
		{
			int newcapacity = _capacity * 2;
			DataType* temp = (DataType*)realloc(_array, newcapacity *
				sizeof(DataType));
			if (temp == NULL)
			{
				perror("realloc申请空间失败!!!");
				return;
			}
			_array = temp;
			_capacity = newcapacity;
		}
	}
private:
	DataType* _array;
	int _capacity;
	int _size;
};
int main()
{
	Stack s1;
	s1.Push(1);
	s1.Push(2);
	s1.Push(3);
	s1.Push(4);
	Stack s2(s1);//这条语句会报错.
	return 0;
}

运行结果:
C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法
原因:
因为编译器默认生成的拷贝构造是浅拷贝,这里两个对象的_array也就指向了同一块内存空间,但是两个对象的声生命周期结束时,会调用各自的析构函数,这也就导致对同一块空间进行了释放操作.
解决方法:
显示定义一个拷贝构造函数.

	Stack(const Stack& S)//深拷贝
	{
		_array = (int*)malloc(sizeof(int) * S._capacity);
		if (NULL == _array)
		{
			perror("malloc申请空间失败!!!");
			return;
		}
		memcpy(S._array,_array,sizeof(int)*S._size);
		_capacity = S._capacity;
		_size = S._size;
	}

总结:

拷贝构造使用场景:

  • 使用已存在对象创建新对象
  • 函数参数类型为类类型对象
  • 函数返回值类型为类类型对象
  1. 拷贝构造函数是构造函数的一个重载形式。
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错,因为会引发无穷递归调用。
  3. 当一个对象作为参数传递给函数时,拷贝构造函数会被调用来创建一个新的对象,该新对象与传递的对象具有相同的属性和属性值,但是它们在内存中是独立的。
  4. 若未显式定义,编译器会生成默认的拷贝构造函数。 默认的拷贝构造函数对象按内存存储按字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝.

二、赋值运算符重载(“=”)

2.1 运算符重载的介绍

class Date//日期类
{
public:
	Date(int year = 2023, int month = 10, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
private:
	int _year;
	int _month;
	int _day;
};
void test1()
{
	Date d1(2023, 7, 28);
	Date d2;
	if (d2 == d1)
	{
		cout << "d1=d2";
	}
	if (d1 < d2)
	{
		cout << "d1<d2";
	}
}

C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法

自定义类型是无法像内置类型一样比较大小和使用一些常规运算符的.
为什么呢?
C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法
因为自定义类型是用户自己定义的,编译器不知道该如何进行比较.那编译器太笨了吧,日期按 年-月-日依次比较不就行了?
个人理解:

  1. 格局打开,如果是别的类呢?比如:person是按名字还是按职位,还是按什么?你不告诉编译器如何比较,编译器也很无奈,不敢瞎搞的.
  2. 编译器咋知道你year是年,要是牛牛用nian来命名,他也能识别出来是年吗?

综上,自定义类型如何进行运算比较,只有用户自己知道,所以用户需要自己来设计规则.

C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其返回值类型.

函数名:关键字operator+需要重载的运算符符号。
operator+ 需要重载的运算符

注意事项:

  • 不能通过连接其他符号来创建新的操作符:
    示例:operator@

  • 重载操作符必须有一个类类型参数
    运算符重载是通过类的成员函数或全局函数来实现的,而这些函数必须具有特定的参数列表。
    对于成员函数的重载操作符,至少需要一个类类型参数,它表示操作符的左操作数。例如,对于二元操作符(如 +、-、* 等),成员函数的参数列表通常还包括一个非常量引用或常量引用,表示操作符的右操作数。

  • 用于内置类型的运算符,其含义不能改变:
    例如:内置的整型*不要实现为了/,害人是不对的.

  • 作为类成员函数重载时,其形参看起来比操作数数目少1一个,因为成员函数的第一个参数为隐藏的this .

  • 注意以下5个运算符不能重载。“.*” (点星) 、" :: " sizeof ? : .

在C++中,有一些操作符是不能被重载的,包括以下几种情况:

  1. ::(作用域解析操作符):作用域解析操作符用于指定命名空间、类或结构的作用域,并访问其成员。它不能被重载,因为它的含义在语言中已经固定不可更改。

  2. .*(指针到成员操作符)和 ->*(指向成员指针的操作符):这些操作符用于访问类的成员指针。它们存储了一个指向类成员的指针,并用于在运行时访问该成员。它们也不能被重载。

  3. sizeof(大小操作符):sizeof操作符用于获取一个对象或类型的大小(以字节为单位)。它是一个编译时的操作符,不能在运行时被重载。因为在编译时就已经确定了对象或类型的大小。

  4. ?:(条件操作符,即三目运算符):条件操作符是一个三元操作符,用于根据条件选择不同的表达式。它不能被重载,因为它的语法和含义已经在语言中定义好了。

  5. .C++中,点操作符(“.”)是用来访问对象的成员的,而它本身是不能被重载的。点操作符的行为在语言中是固定的,无法通过重载来改变。

2.2 赋值运算符重载:

(1)编译器自动生成的 “赋值运算符重载”

class Date//日期类
{
public:
	Date(int year = 2023, int month = 10, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	void print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};


void test1()
{
	Date d1(2023, 7, 28);
	Date d2;
	d1.print();
	d2.print();
	cout << endl;

	d2 = d1;

	d1.print();
	d2.print();

}
int main()
{
	test1();
	return 0;
}

C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法

赋值运算符只能重载成类的成员函数不能重载成全局函数:
原因:

赋值运算符如果不显式实现(自己定义),编译器会生成一个默认的。此时用户再在类外自己实现一个全局的赋值运算符重载,就和编译器在类中生成的默认赋值运算符重载冲突了,故赋值运算符重载只能是类的成员函数。
C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法

那编译器会生成一个默认赋值运算符重载会做什么事情呢?

以值的方式逐字节拷贝。注意:内置类型成员变量是直接赋值的,而自定义类型成员变量需要调用对应类的赋值运算符重载完成赋值。

当然对于日期类这种只需要浅拷贝的类来说,编译器默认生成就已经足够了,但是像stack类,同样引发深浅拷贝的问题.

三、最后的两个天选之子

哈哈哈,期待到最后的两个默认成员函数其实没什么要讲解的.

  1. 取地址操作符重载operator&()
  2. const取地址操作符重载operator&()const
    这两个默认成员函数一般不用重新定义 ,编译器默认会生成。
class Date
{ 
public :

 Date* operator&()
 {
 	return this ;
 }
 
 const Date* operator&()const
 {
 	return this ;
 }
private :
 int _year ; // 年
 int _month ; // 月
 int _day ; // 日
};

这两个运算符一般不需要重载,使用编译器生成的默认取地址的重载即可除非你想搞点特殊的,返回一个特定的特殊地址.

本篇内容到此讲解完了,后续介绍日期类的具体实现,方便大家更好的理解类和对象的知识,实战才能锻炼水平哦.
C++的六大“天选之子“拷贝构造与与运算符重载,C++,c++,开发语言,c语言,算法文章来源地址https://www.toymoban.com/news/detail-635623.html

到了这里,关于C++的六大“天选之子“拷贝构造与与运算符重载的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【C++】构造函数,析构函数,拷贝构造,运算符重载,const 成员

    默认成员函数:如果不显示,编译器默认生成 构造函数:是一个特殊的 成员函数 ,函数名与类名相同,专门用于 初始化类对象 函数名与类名相同 无返回值 ,没有被声明为void类型 对象实例化时 编译器自动调用 , Date d1 ,或 Date d2(2023, 4, 21) 构造函数可以重载,一个类中可以

    2023年04月24日
    浏览(69)
  • 【C++】C++入门—初识构造函数 , 析构函数,拷贝构造函数,赋值运算符重载

    如果一个类中什么成员都没有,简称为空类。 空类中真的什么都没有吗? 并不是 任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。 默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数 我们实现了,编译器就不会生成了 构造函数是

    2024年02月21日
    浏览(50)
  • 【C++学习】类和对象 | 拷贝构造 | 探索拷贝构造函数为什么需要引用传参 | 深拷贝 | 初识运算符重载

    上一篇文章我们开始学习类内的默认成员函数, 这里是传送门,有兴趣可以去看看:http://t.csdn.cn/iXdpH 这篇文章我们继续来学习类和对象的知识。 目录 写在前面: 1. 拷贝构造 2. 拷贝构造函数为什么需要引用传参? 3. 深拷贝 4. 初识运算符重载 写在最后: 我们在创建一个对

    2024年02月11日
    浏览(53)
  • 【C++】类和对象(中)---拷贝构造函数、赋值运算符重载

    个人主页:平行线也会相交💪 欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 平行线也会相交 原创 收录于专栏【C++之路】💌 本专栏旨在记录C++的学习路线,望对大家有所帮助🙇‍ 希望我们一起努力、成长,共同进步。🍓 拷贝构造函数,又称复制构造函数,是一种特殊的

    2024年02月05日
    浏览(49)
  • 【C++基础(六)】类和对象(中) --拷贝构造,运算符重载

    💓博主CSDN主页:杭电码农-NEO💓   ⏩专栏分类:C++初阶之路⏪   🚚代码仓库:NEO的学习日记🚚   🌹关注我🫵带你学习C++   🔝🔝 本章重点: 本篇文章将详细讲解拷贝构造函数 和运算符重载,并介绍const成员的概念 拷贝构造函数和运算符重载 是类和对象中六大默认成员函数

    2024年02月14日
    浏览(43)
  • 【C++】:类和对象(中)之拷贝构造函数+赋值运算符重载

    在现实生活中,可能存在一个与你一样的自己,我们称其为双胞胎 那在创建对象时,可否创建一个与已存在对象一某一样的新对象呢? 拷贝构造函数:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存在的类类型对象创建新对象时由编译器自动调

    2024年02月06日
    浏览(47)
  • C++ -3- 类和对象 (中) | 拷贝构造函数 & 赋值运算符重载

    示例: 拷贝初始化构造函数的作用是将一个已知对象的数据成员值拷贝给正在创建的另一个同类的对象 无穷递归 ? Date(Date d){……} 首先,分析 传值传参的过程 传引用传参 : 没有拷贝 的过程,直接传 传值传参: 内置类型 编译器可以直接拷贝(浅拷贝/值拷贝——一个字节

    2023年04月19日
    浏览(80)
  • 【C++初阶】四、类和对象(构造函数、析构函数、拷贝构造函数、赋值运算符重载函数)

    ========================================================================= 相关代码gitee自取 : C语言学习日记: 加油努力 (gitee.com)  ========================================================================= 接上期 : 【C++初阶】三、类和对象 (面向过程、class类、类的访问限定符和封装、类的实例化、类对象模

    2024年02月05日
    浏览(60)
  • 【C++】类和对象(中)之拷贝构造与运算符、操作符重载

    👀 樊梓慕: 个人主页  🎥 个人专栏: 《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》《C++》 🌝 每一个不曾起舞的日子,都是对生命的辜负 我们继续学习默认成员函数,本篇文章博主带来的是拷贝构造函数与运算符、操作符重载的讲解,并且还有

    2024年02月05日
    浏览(54)
  • 【C++】类和对象③(类的默认成员函数:拷贝构造函数 | 赋值运算符重载)

    🔥 个人主页: Forcible Bug Maker 🔥 专栏: C++ 目录 前言 拷贝构造函数 概念 拷贝构造函数的特性及用法 赋值运算符重载 运算符重载 赋值运算符重载 结语 本篇主要内容:类的6个默认成员函数中的 拷贝构造函数 和 赋值运算符重载 在上篇文章中我们讲到了类的默认成员函数的

    2024年04月17日
    浏览(48)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包