【C++第三课 - 类和对象中】构造函数、析构函数、拷贝构造函数

目录

  • 类的6个默认成员函数
    • 构造函数
      • 自己写的构造函数
      • 默认生成的构造函数
    • 析构函数
      • 概念
      • 特征
    • 拷贝构造函数
      • 特征
    • 运算符重载
      • == 、 >、 <=
      • +=
      • +
    • 赋值重载
    • Date类的完善
      • 构造函数的完善
      • 用+复用+=

类的6个默认成员函数

默认成员函数:不写编译器也会默认生成一份
在这里插入图片描述

构造函数

自己写的构造函数

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任
并不是开空间创建对象,而是初始化对象
其特征如下:

  1. 函数名与类名相同。
  2. 无返回值,不需要写void
  3. 对象实例化时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。
  5. . 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦
    用户显式定义编译器将不再生成。
  6. 关于编译器生成的默认成员函数,很多童鞋会有疑惑:不实现构造函数的情况下,编译器会
    生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默
    认构造函数,但是d对象_year/_month/_day,依旧是随机值。也就说在这里编译器生成的
    默认构造函数并没有什么用??
    解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类
    型,如:int/char…,自定义类型就是我们使用class/struct/union等自己定义的类型,看看
    下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认成员
    函数。
  7. 无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。
    注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为
    是默认构造函数。
#include <iostream>
using namespace std;

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

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

int main()
{
	Date d1;
	Date d2(2023, 1, 24);
	d1.Print();
	d2.Print();

	return 0;
}

在这里插入图片描述

对于没有参数的初始化对象时,不能写成下面那样,因为无法与函数声明区分
Date d1()

也可以用缺省函数,下面两个函数构成函数重载,但是无参调用的时候会产生歧义

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

默认生成的构造函数

默认构造函数:编译器默认生成的、无参的构造函数、全缺省的构造函数(可以不传参的都叫默认构造),这三个函数不能同时存在,因为会存在调用歧义。
如果不写构造函数,有没有构造函数
默认生成的,但此时是随机值

class Date
{
public:
	void Print()
	{
		cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _day;
	int _month;
	int _year;
};

int main()
{
	Date d1;
	d1.Print();

	return 0;
}

在这里插入图片描述
对于栈的初始函数来说,初始化的也是随机值

class Stack
{
public:

private:
	int* _a;
	int _top;
	int _capacity;
};

int main()
{
	Stack s1;

	return 0;
}

在这里插入图片描述
但对于像MyQueue的构造函数就初始化了
在这里插入图片描述

在这里插入图片描述
规则
内置类型:int/double/…指针,eg:Date* p是内置类型
自定义类型: class struct…
默认生成的构造函数,对于内置类型成员不做处理(看编译器,建议当成不处理),自定义类型会取调用它的默认构造(调用无参的默认构造,如果自定义类型没有默认构造 - 初始化列表,类和对象下讲)
对于这个缺陷C++11提供如下解决方法,下面这个写法还是声明,给的缺省值
在这里插入图片描述

析构函数

概念

析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由
编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。

特征

析构函数是特殊的成员函数,其特征如下:

  1. 析构函数名是在类名前加上字符 ~。
  2. 无参数无返回值类型。
  3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构
    函数不能重载
  4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
  5. 编译器生成的默认析构函数,对自定类型成员调用它的析构函数。
  6. 如果类中没有申请资源时,析构函数可以不写,直接使用编译器生成的默认析构函数,比如
    Date类;有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类
    日期类不需要写析构,栈需要写析构
class Date
{
public:
	Date(int day = 1, int month = 1, int year = 1)
	{
		_day = day;
		_month = month;
		_year = year;
	}

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

	~Date()
	{
		cout << "~Date()" << endl;
	}
private:
	int _day = 1;
	int _month = 1;
	int _year = 1;
};


int main()
{
	Date d1;
	d1.Print();

	return 0;
}

在这里插入图片描述
在这里插入图片描述

拷贝构造函数

在这里插入图片描述
浅拷贝时,st和st1对象会导致对同一块空间的重复释放
解决方法:自定义类型对象拷贝时,调用一个函数,这个函数就叫拷贝构造 - 深拷贝。
(1)传参的时候
(2)初始化构造的时候Date d2(d1)

特征

  1. 拷贝构造函数是构造函数的一个重载形式
  2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错
    因为会引发无穷递归调用。.0
  3. 默认生成的拷贝构造函数:对内置类型会完成值拷贝,自定义对象回去调用它的拷贝对象。
    在这里插入图片描述
    像下面所示,st1与st中的_a是指向同一块空间,当这两个对象被释放时,会对_a所指的这段空间释放两次,从而造成错误,拷贝构造主要是解决这个问题的深拷贝
    在这里插入图片描述
    在这里插入图片描述
class Stack
{
public:
	Stack()
	{
		//...
	}
	Stack(const Stack& stt)
	{
		_a = (int*)malloc(sizeof(int) * stt._capacity);
		if (_a == nullptr)
		{
			perror("malloc fail");
			exit(-1);
		}
		memcpy(_a, stt._a, sizeof(int) * stt._top);
		_top = stt._top;
		_capacity = stt._capacity;
	}
	~Stack()
	{
		cout << "~Stack()" << endl;
	}
private:
	int* _a;
	int _top;
	int _capacity;
};

在这里插入图片描述

1、被拷贝的对象前面加const,防止意外的改变

运算符重载

对于+、-、*、/、>、<等等,内置类型可以直接使用,自定义类型无法使用
解决方法:(1)写一个函数 (2)使用运算符重载
运算符重载:operator+运算符 ,使用方法:直接使用运算符

函数重载:允许参数不同的同名函数存在
运算符重载:自定义类型可以直接使用运算符

== 、 >、 <=

class Date
{
public:
	Date(int year = 1, int month = 1, int day = 1)
	{
		_year = year;
		_month = month;
		_day = day;
	}
	
public:
	int _year;
	int _month;
	int _day;
};
bool operator==(Date x, Date y)
{
	return x._year == y._year && x._month == y._month && x._day == y._day;
}
bool operator>(Date x, Date y)
{
	if (x._year > y._year)
		return true;
	else if (x._year == y._year && x._month > y._month)
		return true;
	else if (x._year == y._year && x._month == y._month && x._day > y._day)
		return true;
	return false;
}
bool operator<=(Date x, Date y)
{
	return ~(x > y);
}

int main()
{
	Date d1(2001, 3, 29);
	Date d2(2024, 3, 1);
	cout << (d1 > d2) << endl;
	cout << (d1 == d2) << endl;
	cout << (d1 <= d2) << endl;
	return 0;
}

在这里插入图片描述
报错的原因:因为流提取运算符的优先级大于>,因此加个括号就没事了
在这里插入图片描述
**此时程序的缺陷 :
1、运算符重载函数的参数那,调用了拷贝构造 --> 用&
2、为了在函数里访问类的成员变量,把成员变量设置 成了公有 --> 在类里面设置一些访问成员的函数;将运算符重载函数放到类里面
**
缺陷1修改

bool operator==(const Date& x, const Date& y)
{
	return x._year == y._year && x._month == y._month && x._day == y._day;
}
bool operator>(const Date& x, const Date& y)
{
	if (x._year > y._year)
		return true;
	else if (x._year == y._year && x._month > y._month)
		return true;
	else if (x._year == y._year && x._month == y._month && x._day > y._day)
		return true;
	return false;
}
bool operator<=(const Date& x, const Date& y)
{
	return ~(x > y);
}

缺陷2修改

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

	bool operator==(const Date& y)
	{
		return _year == y._year && _month == y._month && _day == y._day;
	}
	bool operator>(const Date& y)
	{
		if (_year > y._year)
			return true;
		else if (_year == y._year && _month > y._month)
			return true;
		else if (_year == y._year && _month == y._month && _day > y._day)
			return true;
		return false;
	}
	bool operator<=(const Date& y)
	{
		return ~(*this > y);
	}
	
private:
	int _year;
	int _month;
	int _day;
};

在这里插入图片描述
也可以d1.operator>(d2)这样显示的调用
这个类还可以些哪些运算符重载,这个取决于哪些运算符对于这个类是有意义的
eg:日期-日期、日期+=天数、日期+天数

+=

int GetMonthDay(int year, int month)
	{
		assert(year >= 1 && month >= 1 && day >= 1);
		int arr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		if (month == 2 && (((year % 4 == 0) && (year % 100 != 0)) || year % 400 == 0))
			return 29;
		return arr[month];

	}

Date& operator+=(int day)
	{
		_day += day;
		while (_day > GetMonthDay())
		{
			_day -= GetMonthDay();
			_month++;
			if (_month > 12)
			{
				_year++;
				_month = 1;
			}

		}
		return *this;

	}

细节
根据内置类型的定义,+=是有返回值的,因此自定义类型也应该有返回值
在这里插入图片描述

在这里插入图片描述

+

int GetMonthDay(int year, int month)
	{
		assert(year >= 1 && month >= 1 && day >= 1);
		int arr[13] = { 0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
		if (month == 2 && (((year % 4 == 0) && (year % 100 != 0)) || year % 400 == 0))
			return 29;
		return arr[month];

	}
Date operator+(int day)
	{
		Date tmp(*this);
		tmp._day += day;
		while (tmp._day > GetMonthDay(tmp._year, tmp._month))
		{
			tmp._day -= GetMonthDay(tmp._year, tmp._month);
			tmp._month++;
			if (tmp._month > 12)
			{
				tmp._year++;
				tmp._month = 1;
			}

		}
		return tmp;

	}

赋值重载

operator= 我们不写,编译器回生成默认的operator=。跟拷贝构造的行为类似,内置类型值拷贝,自定义类型调用他的赋值
Date、MyQueue可以不用写,默认生成的operator=就可以用
赋值重载:(重载运算符)两个已经存在的对象拷贝
拷贝构造:一个已经存在的对象去拷贝初始化另一个对象

缺省参数不能同时出现在声明与定义里面,只能在声明中定义

Date& operator=(const Date& y);

Date& Date::operator=(const Date& y)
{
	if (this != &y)
	{
		_year = y._year;
		_month = y._month;
		_day = y._day;
	}

	return *this;
}

Date类的完善

构造函数的完善

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

	if (_year < 1 || _month > 13 || _month < 1 || day < 1 || day > GetMonthDay(_year, _month))
	{
		print();
		cout << "日期非法" << endl;
	}
}

用+复用+=

复用1

Date& Date::operator+=(int day)
{
	*this = *this + day;
	return *this;

}
Date Date::operator+(int day)
{
	Date tmp(*this);
	tmp._day += day;
	while (tmp._day > GetMonthDay(tmp._year, tmp._month))
	{
		tmp._day -= GetMonthDay(tmp._year, tmp._month);
		tmp._month++;
		if (tmp._month > 12)
		{
			tmp._year++;
			tmp._month = 1;
		}

	}
	return tmp;

}

在这里插入图片描述

复用2

Date& Date::operator+=(int day)
{
	_day += day;
	while (_day > GetMonthDay(_year, _month))
	{
		_day -= GetMonthDay(_year, _month);
		_month++;
		if (_month > 12)
		{
			_year++;
			_month = 1;
		}

	}
	return *this;

}
Date Date::operator+(int day)
{
	Date tmp(*this);
	
	tmp += day;
	return tmp;

}

在这里插入图片描述

复用2要比复用1效率更高

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

uniapp制作--简单的tab切换

一、实现思路 在UniApp中&#xff0c;可以使用v-if来控制Tab栏并进行切换。 创建一个方法来控制点击时的效果。 二、实现步骤 ①view部分展示 <!-- tab选项 --><view class"select-area"><view class"select-top"><view clas…

恒创科技2024开年采购海外服务器配置及价格汇总

喜迎龙年&#xff0c;开年采购开好局。值企业开工采购浪潮来袭之际&#xff0c;为进一步满足个人开发者到中小企业等各类型用户的选购需求&#xff0c;中国香港及亚太数据中心领先服务商恒创科技启动了“ 2024 开年采购开好局”大促活动&#xff0c;该活动已于 3 月 5 日正式上…

消费品亚马逊化学测试要求有哪些?RSL,双酚A(BPA)REACH,CPSIA等

消费品亚马逊化学测试要求有&#xff1a;RSL&#xff0c;双酚A&#xff08;BPA&#xff09;REACH&#xff0c;CPSIA&#xff0c;加州65&#xff0c;等 亚马逊对所有在其官方网站上架产品的化学物质和重金属限制&#xff0c;以及亚马逊如何检查符合欧盟和美国的消费品法规中的第…

【科研基础】插图摘录

FedSL: Federated Split Learning for Collaborative Healthcare Analytics on Resource-Constrained Wearable IoMT Devices Blockchain-Based Trustworthy and Efficient Hierarchical Federated Learning for UAV-Enabled IoT Networks

langchain学习笔记(十一)

关于langchain中的memory&#xff0c;即对话历史&#xff08;message history&#xff09; 1、 Add message history (memory) | &#x1f99c;️&#x1f517; Langchain RunnableWithMessageHistory&#xff0c;可用于任何的chain中添加对话历史&#xff0c;将以下之一作为…

怎么采集GBK或GB2312等特殊字符编码的网站数据

如果要采集的网站是GBK或GB2312等特殊字符编码&#xff0c;采集结果可能是一堆看不懂的文字或乱码&#xff0c;无法使用。 通常网页文章采集工具有字符编码选项&#xff0c;默认是UTF-8&#xff08;现在大部分网站都是&#xff09;&#xff0c;改选为GBK或GB2312字符编码即可&…

c++数据结构算法复习基础-- 3 --线性表-单向链表-笔试面试常见问题

1、单链表逆序 思路图 代码实现 //著: 链表结构里记得加 friend void ReverseLink(Clink& link); void ReverseLink(Clink& link) {Node* p link.head_->next_;while( p nullptr){return;}Node* q p->next_;link.head_->next_ nullptr;while(p ! nullpt…

Java解决杨辉三角

Java解决杨辉三角 01 题目 给定一个非负整数 *numRows&#xff0c;*生成「杨辉三角」的前 numRows 行。 在「杨辉三角」中&#xff0c;每个数是它左上方和右上方的数的和。 示例 1: 输入: numRows 5 输出: [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1]]示例 2: 输入: numRo…

亚信安慧AntDB:编织数据丝路,缔造创新篇章

亚信安慧AntDB作为一款具备国产化升级改造经验的数据库系统&#xff0c;在15年的平稳运行中积累了丰富经验。通过持续的创新和技术进步&#xff0c;AntDB不断优化性能和功能&#xff0c;满足用户的需求&#xff0c;与国际先进数据库系统保持竞争力。 AntDB秉承着与用户和行业保…

结合大象机器人六轴协作机械臂myCobot 280 ,解决特定的自动化任务和挑战!(下)

Limo Pro 小车建图导航 引言 前景提要&#xff1a;我们在上文介绍了使用LIMO cobot 实现一个能够执行复杂任务的复合机器人系统的应用场景的项目&#xff0c;从以下三个方面&#xff1a;概念设计、系统架构以及关键组件。 本文主要深入项目内核的主要部分&#xff0c;同样也主要…

python自动化管理和zabbix监控网络设备(zabbix部署监控网络设备以及验证部分)

目录 前言 一、Zabbix搭建 二、FW1 三、python脚本 四、core-sw1 五、core-sw2 六、DMZ-sw1 前言 详细配置视频解析访问&#xff1a;白帽小丑的个人空间-白帽小丑个人主页-哔哩哔哩视频 一、Zabbix搭建 sed -i s/SELINUXenforcing/SELINUXdisable/ /etc/selinux/config…

力扣——盛最多水的容器

题目描述&#xff1a; 给定一个长度为 n 的整数数组 height 。有 n 条垂线&#xff0c;第 i 条线的两个端点是 (i, 0) 和 (i, height[i]) 。 找出其中的两条线&#xff0c;使得它们与 x 轴共同构成的容器可以容纳最多的水。 返回容器可以储存的最大水量。 说明&#xff1a;…

【论文笔记】Gemma: Open Models Based on Gemini Research and Technology

Gemma 日期: March 5, 2024 平台: CSDN, 知乎 状态: Writing Gemma: Open Models Based on Gemini Research and Technology 谷歌最近放出的Gemma模型【模型名字来源于拉丁文gemma&#xff0c;意为宝石】采用的是与先前Gemini相同的架构。这次谷歌开源了两个规模的模型&…

Golang Copy()方法学习

前言 主要是涉及到深浅拷贝相关的&#xff0c;但是在看的一个资料过程中发现他有错…并且一系列&#xff0c;复制粘贴他的&#xff0c;也都错了。 错误文章指路 很显然&#xff0c;Copy是深拷贝啊&#xff01;&#xff01;&#xff01; Copy功能 copy的代码很少&#xff0c…

MySQL基础-----SQL语句之DQL数据查询语句(上篇)

目录 前言 select基本语法 一、基础查询 1.查询多个字段 2.字段设置别名 3.去除重复记录 案例 二、条件查询 1.语法 2.条件 案例 三、聚合函数 1.聚合函数 2.语法 案例 前言 前面我们学习了DML和DDL语句&#xff0c;那么本期我们学习数据查询的语句&#xff08;DQ…

启英泰伦「离线自然说」:让照明语音交互更自然、更便捷

随着科技的不断发展&#xff0c;智能家居已经成为现代生活的一部分。其中&#xff0c;智能照明作为智能家居的重要组成部分&#xff0c;为人们带来了更加便捷、舒适的照明体验。然而&#xff0c;传统的离线语音交互技术在智能照明领域的应用一直受到词条存储量的限制&#xff0…

把握职场脉搏,明智选择赛道

选择比努力更重要。男怕入错行&#xff0c;进入IT行业的你已经成功一半了&#xff0c;但IT业也细分了诸多赛道&#xff0c;应该如何兼顾选择呢&#xff1f;在快速发展的科技行业中&#xff0c;程序员面临着众多选择。如何选择最适合自己的职业赛道&#xff0c;成为许多程序员关…

Verilog Coding Styles For Improved Simulation Efficiency论文学习记录

原文基于Verilog-XL仿真器&#xff0c;测试了以下几种方式对仿真效率的影响。 1. 使用 Case 语句而不是 if / else if 语句 八选一多路选择器 case 实现效率比 if / else if 提升 6% 。 2. 如果可以尽量不使用 begin end 语句 使用 begin end 的 ff 触发器比不使用 begin end …

校园气象站—为学校的科普教育提供有力的支持

TH-XQ3校园气象站是一种针对校园环境的气象监测设备&#xff0c;通过现场自动监测的方式&#xff0c;对雨量、风向、风速、气温、相对湿度、气压、太阳辐射、噪声等气候要素进行全天候现场监测&#xff0c;同时将监测数据及时传递给学生和校园管理人员。校园气象站的建设不仅可…

python使用zmail实现邮件发送

一&#xff1a;zmail介绍 1、Zmail的优势 自动填充大多数导致服务端拒信的头信息&#xff08;From To LocalHost之类的)将一个字典映射为email&#xff0c;构造信件就像构造字典一样简单自动寻找邮件服务商端口号地址&#xff0c;自动选择合适的协议&#xff08;经过认证的&am…