类和对象(3)

news2024/11/18 19:39:07

文章目录

  • 1.回顾上节
  • 2. 拷贝构造
  • 3. 运算符重载(非常重要)
  • 4. 赋值运算符重载

1.回顾上节

在这里插入图片描述
默认成员函数:我们不写,编译器自动生成。我们不写,编译器不会自动生成
默认生成构造和析构:

  1. 对于内置类型不做处理
  2. 对于自定义类型会调用对应的构造/析构。

2. 拷贝构造

#include <iostream>
using namespace std;
class Date
{
public:
	Date(int year=1, int month=1, int day=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//拷贝构造,函数名和类名相同
	//拷贝构造的参数为什么不能是传值?
	//C++自定义类型的成员在这个地方传值需要调用拷贝构造,无穷无尽
	//因此自定义类型必须调用拷贝构造,所以要用引用&。最好加const
	Date(const 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;
	Date d2(d1);
	d1.Print();
	d2.Print();//这时改变_year等会改变d1

	return 0;
}

在这里插入图片描述
以下为不调用拷贝构造时,会默认生成拷贝构造
在这里插入图片描述
内置类型会处理,因此日期类不需要自己去写拷贝构造
自定义类型会去调用他的拷贝构造


	Stack st1;
	Stack st2(st1);
	//栈中保持后进先出,后定义的先析构。
	//st1变成野指针。

指向同一块空间的问题:

  1. 插入删除数据会互相影响
  2. 析构两次,程序崩溃。
    默认的拷贝:
    浅拷贝/值拷贝
    **深拷贝:**让各自有各自独立的空间,开另外的空间,把值拷贝下来。
    更深入层次的拷贝
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
				exit(-1);
		}
		_size = 0;
		_capacity = capacity;
	}
void Push(const DataType& data)
{
	_array[_size] = data;
	_size++;
}
Stack(const Stack& st)//深拷贝
{
	_array = (DataType*)malloc(sizeof(DataType) * st._capacity);
	if (nullptr == _array)
	{
		perror("malloc申请空间失败");
		exit(-1);//直接终止程序
	}
	//拷贝数组空间上的值
	memcpy(_array, st._array, sizeof(DataType) * st._size);
	_size = st._size;
	_capacity = st._capacity;
}
~Stack()
{
	if (_array)
	{
		free(_array);
		_array = nullptr;
		_capacity = 0;
		_size = 0;
	}
}
private:
	DataType *_array;
	size_t _size;
	size_t _capacity;
	};
int main()
{
	Stack st1;
	st1.Push(1);
	st1.Push(2);
	st1.Push(3);
	st1.Push(4);

	Stack st2(st1);
	//栈中保持后进先出,后定义的先析构。
	//没有写拷贝构造,编译器自动生成了一个

	return 0;
}

什么情况下需要写拷贝构造呢?
不能用指针来衡量,如果自己实现了析构函数释放了空间,就需要实现拷贝构造。

  1. 对于内置类型完成浅拷贝/值拷贝–按byte一个个拷贝
  2. 自定义类型,去调用这个成员拷贝构造/赋值重载
    2种大方向的特性
typedef int DataType;
class Stack
{
public:
	Stack(size_t capacity = 10)
	{
		_array = (DataType*)malloc(capacity * sizeof(DataType));
		if (nullptr == _array)
		{
			perror("malloc申请空间失败");
				exit(-1);
		}
		_size = 0;
		_capacity = capacity;
	}
void Push(const DataType& data)
{
	_array[_size] = data;
	_size++;
}
Stack(const Stack& st)
{//拷贝构造对内置类型完成值拷贝或者浅拷贝。
	cout << "Stack(const Stack& st)" << endl;
	_array = (DataType*)malloc(sizeof(DataType) * st._capacity);
	if (nullptr == _array)
	{
		perror("malloc申请空间失败");
		exit(-1);//直接终止程序
	}
	//拷贝数组空间上的值
	memcpy(_array, st._array, sizeof(DataType) * st._size);
	_size = st._size;
	_capacity = st._capacity;
}
~Stack()
{
	if (_array)
	{
		free(_array);
		_array = nullptr;
		_capacity = 0;
		_size = 0;
	}
}


private:
	DataType *_array;
	size_t _size;
	size_t _capacity;
	};
//对于自定义类型,不需要写拷贝构造和构造。不写编译器会自动生成构造函数,构造函数符合我们的需求
class MyQueue
{
public:
	//默认生成构造和析构
	//默认生成拷贝构造
private:
	Stack _pushST;
	Stack _popST;
	int _size = 0;//缺省值,用缺省值处理
};
int main()
{
	Stack st1;
	st1.Push(1);
	st1.Push(2);
	st1.Push(3);
	st1.Push(4);

	Stack st2(st1);
	//栈中保持后进先出,后定义的先析构。
	//没有写拷贝构造,编译器自动生成了一个
	MyQueue q1;
	//调用了拷贝构造
	MyQueue q2(q1);
	return 0;
}

在这里插入图片描述
那些场景存在拷贝构造
Date d2(d1);
Date d3=d1;//拷贝构造
传返回值的过程中能用引用就用引用,减少拷贝。除非就是想让他自己调用拷贝构造,拷贝一份独立的出来
参数基本都可以用引用,返回值不一定。局部对象不能用引用。

Date Test(Date d)
{
  Date temp(d);
  return temp;
}

3. 运算符重载(非常重要)

为了增强程序的可读性,是具有特殊函数名的函数,也有其返回值类型函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似

  • 比较日期大小
    内置类型可以比较大小,自定义类型不可以
  • 运算符重载和函数重载无关:
    函数重载是支持参数名相同,参数不同的函数,随时可以用
    运算符重载:自定义类型对象可以使用运算符。
    两个地方都用了重载,但两个地方没有关联
  • 运算符重载:实现一个函数。新增一个关键字operator加操作符有参数有返回值
  • 参数和返回值根据运算符确定。有的有返回值有的没有。
  • 运算符有几个操作数就有几个参数
class Date
{
public:
	Date(int year=1, int month=1, int day=1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	//private:
	int _year;
	int _month;
	int _day;
	
};

bool operator==(const Date& d1, const Date& d2)//运算符重载可以实现在全局。
{
	return d1._year == d2._year
		&& d1._month == d2._month
		&& d1._day == d2._day;
}
int main()
{
	Date d1(2023, 9, 14);
	Date d2(2023, 9, 14);

	cout<<operator==(d1, d2)<<endl;
	cout <<( d1 == d2) << endl;//全局函数,转换成调用这个函数operator==(d1,d2);和上一行一样
	
	//运算符优先级<<高于==
	return 0;
}

在这里插入图片描述
当放成私有时

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

直接把函数放在类里面。类外面受到访问限定符的限制,放到类里面就解决问题了。但是会报错
在这里插入图片描述
其中还有隐藏的参数(2个):this
成员函数调用的方式也不同了。

//d1==d2转换为d1.operator==(d2)
bool operator==(const Date& d)
	{
	//this:d1;d:d2
		return this->_year == d._year
			&& _month == d._month
			&& _day == d._day;
	}

	cout<<d1.operator==(d2)<<endl;
	cout <<( d1 == d2) << endl;//成员函数转换成调用这个函数d1.operator==(d2);和上一行一样
	

在这里插入图片描述
运算符重载

  1. 函数名:operator+运算符或操作符
  2. 返回值类型/参数:根据需求调用
  3. 不能乱接其他符号创造一个新的操作符,如:operator@
  4. 必须有一个类类型参数**(自定义类型)**
  5. 不能对内置类型重载,其含义不能改变。如内置类型的整型——,不能改变其含义
  6. 作为类成员函数重载时,其形参看起来比操作数目少1,因为成员函数的第一个参数为隐藏的this
  7. .* :: sizeof ?:(三目运算符) .(成员访问) 注意以上5个运算符不能重载,这个经常在笔试选择题中出现
//b1<b2小测
bool operator<(const Date& d)
{
	if (_year < d._year)
	{
		return true;

	}
	else if (_year == d._year && _month < d._month)
	{
		return true;
	}
	else if (_year == d._year && _month == d._month && _day < d._day)
	{
		return true;
	}
	else
	{
		return false;
    }
}

//b1<=b2复用,根据上面有<有=

bool operator<=(const Date& d)
{
	return *this < d || *this == d;
}

//b1>b2,取反。

bool operator>(const Date& d)
{
	return !(*this <= d) ;
}

4. 赋值运算符重载

d1=d2;//是一种拷贝

//d1=d2
void operator=(const Date& d)//不用引用不会无穷递归,但会白白走一次拷贝构造,所以最好加上引用
{

	_year = d._year;
	_month = d._month;
	_day = d._day;
}
d3=d2=d1;//编译不通过d1赋值给d2,d2的返回值传给d3

连续赋值,从右往左赋值。i=j=k; k赋值给j,返回j

Date& operator=(const Date& d)
{

	_year = d._year;
	_month = d._month;
	_day = d._day;
	//*this是d1
	return *this;
	//出了作用域还在,应该加引用。
	//返回值是为了支持连续赋值,保持运算符的特性。
}

d1=d1
自己给自己赋值,可以加一个判断

Date& operator=(const Date& d)//引用
{
 if(this!=&d)//取地址,this是左操作数的地址,d是右操作数的别名,地址相同则不用自己给自己赋值
 {
	_year = d._year;
	_month = d._month;
	_day = d._day;
 }
	return *this;
}

+=支持连续赋值,只要支持连续赋值就都有返回值。。
前置++,d1.operator();
后置++,d2.operator(int);
int仅仅是为了占位,和牵制重载区分

//++d1;
Date& Date::operator++()
{
  Date tmp(*this);
  *this+=1;
  return tmp;
}
//d1++
Date Date::operator++(int)
{
  Date tmp(*this);
 *this+=1;
 return tmp;
}

对于内置类型,前置和后置++没有区别
对于自定义类型,**前置++**效率高,后置++还要拷贝

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1011637.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mysql远程连接失败

先上结论&#xff0c;只提出最容易忽略的地方 服务器是阿里云、腾讯云等平台&#xff0c;平台本身自带的防火墙没有开启iptables规则中禁用了3306&#xff0c;即使你根本没有启用iptables服务 第二条是最离谱的 从这里可以看到&#xff0c;我服务器并未启用 iptables 服务 但…

应用在电子体温计中的国产温度传感芯片

电子体温计由温度传感芯片&#xff0c;液晶显示器&#xff0c;纽扣电池&#xff0c;专用集成电路及其他电子元器件组成。能快速准确地测量人体体温&#xff0c;与传统的水银玻璃体温计相比&#xff0c;具有读数方便&#xff0c;测量时间短&#xff0c;测量精度高&#xff0c;能…

如何分析Apple搜索广告效果

Apple搜索广告提供了一系列指标&#xff0c;报告和功能&#xff0c;可为广告效果、用户行为和关键词有效性提供有价值的见解。通过利用此工具&#xff0c;广告商可以更深入地了解他们的广告活动&#xff0c;优化他们的策略&#xff0c;并取得更好的结果。 1、在研究数据之前&a…

深入解析NLP情感分析技术:从篇章到属性

目录 1. 情感分析概述1.1 什么是情感分析&#xff1f;- 情感分析的定义- 情感分析的应用领域 1.2 为什么情感分析如此重要&#xff1f;- 企业和研究的应用- 社交媒体和公共意见的影响 2. 篇章级情感分析2.1 技术概览- 文本分类的基本概念- 机器学习与深度学习方法- 词嵌入的力量…

webStorm内存溢出问题

手动启动vue项目正常运行&#xff0c;修改部分内容保存后会自动重新run一下&#xff0c; 这个时候就报错内存溢出&#xff0c;然后很悲伤的需要再手动重启一下。 每个人的情况不同&#xff0c;下面几种方法可以都试一试。 1、修改help里的内存配置 &#xff08;图片只参考修改…

puttygen工具ppk文件版本配置

有时一些程序要用到ppk密钥文件&#xff0c;如果用puttygen去生成的话&#xff0c;ppk文件版本是可以配置的&#xff0c;有版本2、版本3&#xff0c;如果出现密钥文件无效&#xff0c;可以试一下选择不用的文件版本。 配置位置&#xff1a;打开puttygen-选择菜单栏Key-选择Para…

差分+差分矩阵(更适合新手宝宝体质)

快速掌握差分以及差分矩阵 文章目录 快速掌握差分以及差分矩阵前言差分差分的定义【官方解释】差分自定义【跟前缀和放在一起理解】差分数组的应用 题目描述差分矩阵【与前缀和矩阵进行比较】差分矩阵定义【官方解释】自定义修改操作【跟前缀和对比】 题目描述代码 前言 之前我…

微信小程序——小程序的API介绍

小程序的宿主环境-API 1.小程序API概述 小程序中的API是由宿主环境提供的&#xff0c;通过这些丰富的小程序API&#xff0c;开发者可以方便的调用微信提供的能力&#xff0c;例如&#xff1a;获取用户信息&#xff0c;本地存储&#xff0c;支付功能等。 2.小程序API的3大分类…

wav文件碎片多删除后恢复案例

wav是微软针对音频提供的一种文件&#xff0c;其本质上和qt类文件&#xff08;如mp4 mov&#xff09;是一样的&#xff0c;都是“容器”类文件。但凡是容器类的文件其关注的点就是制定规则&#xff0c;一切按规则来&#xff08;wav中就是速率、时长、编码类型等&#xff09;。这…

Linux下利用文件IO函数完成多进程复制图片,父进程复制前一半,子进程复制后一半

Linux下利用文件IO函数完成多进程复制图片&#xff0c;父进程复制前一半&#xff0c;子进程复制后一半 一 、概述 在Linux环境下&#xff0c;利用多进程完成图片的复制操作本demo用到了两个进程&#xff0c;一个是主函数所在的父进程&#xff0c;一个在主函数里面创建的子进程…

安装系统作为启动盘的U盘恢复原样

1、插U盘 2、winr——cmd&#xff0c;输入diskpart 3、此电脑——管理——磁盘管理——查看磁盘号&#xff1a;磁盘 1 4、输入&#xff1a;select disk 1——clean 5、磁盘管理——右击新建简单卷——下一步即可

u盘传输数据的时候拔出会怎么样?小心这些危害

U盘是我们日常生活和工作中常使用的一种便携式存储设备。然而&#xff0c;在使用U盘传输数据时&#xff0c;有时我们会不小心将它拔出&#xff0c;而这个看似微不足道的行为实际上可能会带来严重的后果。本文将向您介绍U盘在传输数据时突然拔出可能导致的各种危害&#xff0c;其…

如何恢复U盘里面的已经损坏的数据?

弹出使用驱动器之前&#xff0c;先将U盘格式化的信息框&#xff0c;是Windows系统针对某些特定类型的U盘或移动硬盘的一种常见处理方式。一般来说&#xff0c;如果U盘或移动硬盘出现某些故障或问题&#xff0c;Windows系统会建议用户将其格式化。 格式化是一种常规的操作&…

Kafka消费者组重平衡(二)

文章目录 概要重平衡通知机制消费组组状态消费端重平衡流程Broker端重平衡流程 概要 上一篇Kafka消费者组重平衡主要介绍了重平衡相关的概念&#xff0c;本篇主要梳理重平衡发生的流程。 为了更好地观察&#xff0c;数据准备如下&#xff1a; kafka版本&#xff1a;kafka_2.1…

9.12 C++作业

实现一个图形类&#xff08;Shape&#xff09;&#xff0c;包含受保护成员属性&#xff1a;周长、面积&#xff0c; 公共成员函数&#xff1a;特殊成员函数书写 定义一个圆形类&#xff08;Circle&#xff09;&#xff0c;继承自图形类&#xff0c;包含私有属性&#xff1a;半…

模拟信号电压或电流信号转变频器频率传感器信号隔离变送器0-5V/0-10V/0-20mA/4-20mA转0-5KHz/0-10KHz/1-5KHz

主要特性: 精度等级&#xff1a;0.1 级、0.2 级。产品出厂前已检验校正&#xff0c;用户可以直接使用输 入 &#xff1a;0-5V/0-10V/1-5V,0-10mA/0-20mA/4-20mA 等输出信号&#xff1a;0-5KHz/0-10KHz/1-5KHz 等标准信号辅助电源&#xff1a;5V、9V、12V、15V 或 24V 直流单电…

OpenCV(四十三):Shi-Tomas角点检测

1.Shi-Tomas角点检测原理 Shi-Tomasi&#xff08;也称为Good Features to Track&#xff09;角点检测算法是一种改进的角点检测方法&#xff0c;它基于Harris角点检测算法&#xff0c;并针对一些不足进行了改进。 与Harris角点检测不同&#xff0c;Shi-Tomasi使用了更简化的角点…

PDF怎么合并?这几个方法收藏起来吧

PDF文件是一种非常常见的文档格式&#xff0c;它具有跨平台、易于阅读和打印等优点&#xff0c;因此在生活和工作中得到了广泛的应用。当我们需要将多个PDF文件合并成一个文件时&#xff0c;我们可以采用以下几种方法。 方法一&#xff1a;使用PDF转换工具 我们在电脑上打开迅…

Spring Boot 中的 @CacheEvict 注解使用

Spring Boot 中的 CacheEvict 注解 在 Spring Boot 中&#xff0c;缓存是提高应用性能的重要手段。为了更好地管理缓存&#xff0c;Spring Boot 提供了一系列的缓存注解&#xff0c;其中 CacheEvict 注解用于清空缓存。 本文将介绍 CacheEvict 注解的含义、原理以及如何使用。…

华为云云耀云服务器L实例评测-基于华为云服务器的测试及简单配置

引言 云计算已经成为现代企业和个人的重要组成部分。在云计算市场上&#xff0c;华为云一直以来都以其出色的性能和服务质量而闻名。周末的时候&#xff0c;利用华为云云耀云服务器搭建了一个基于hexo的个人博客&#xff0c;我用的是2核2G的3M带宽的配置&#xff0c;访问起来挺…