C++学习第五天
创作过程中难免有不足,若您发现本文内容有误,恳请不吝赐教。
一、构造函数
问题1
示例1:
#include<iostream>
using namespace std;class A
{
public:A(int a){cout << "Aint(a)" << endl;_a = a;}
private:int _a;
};class Date
{
public://Date(int year, int month, int day)//{// _year = year;// _month = month;// _day = day;//}
private://内置类型int _year;int _month;int _day;//自定义类型A _aa;
};int main()
{Date d1;
}
class A没有提供默认构造函数(不用参数就可以调用的构造).
示例2:
#include<iostream>
using namespace std;class A
{
public:A(int a = 0){cout << "A int(a)" << endl;_a = a;}
private:int _a;
};class Date
{
public://Date(int year, int month, int day)//{// _year = year;// _month = month;// _day = day;//}
private://内置类型int _year;int _month;int _day;//自定义类型A _aa;
};int main()
{Date d1;
}
如果A不提供默认构造,需要使用初始化列表才能解决。当前的学习暂时先通过提供全缺省( A(int a = 0) )来解决这个问题.
简单来说:我们不写编译器生成的默认构造函数,对内置类型不做处理,对自定义类型会调用它的默认构造.
二、默认构造函数
无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。 注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为是默认构造函数。
特点:不传参就可以调用的构造就是默认构造.
三、析构函数
可以简单理解为与构造函数相反的函数,类比Destroy函数.
日期类不需要写析构函数,因为日期类没有资源需要清理,年、月、日属于对象,不需要清理。而像栈这种才需要清理,有指向资源才需要清理。
示例1:
内置类型的成员,不做处理,造成堆上的空间没有释放,造成内存泄漏。
#include<iostream>
using namespace std;typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){_array[_size] = data;_size++;}/*~Stack(){cout << "~Stack()" << endl;free(_array);_array = nullptr;_size = _capacity = 0;}*/
private:// 内置类型DataType* _array;int _capacity;int _size;};void TestStack()
{Stack s;s.Push(1);s.Push(2);
}int main()
{TestStack();return 0;
}
示例2:
自定义类型的成员,会去调用他的析构。
#include<iostream>
using namespace std;class A
{
public:A(int a = 0){cout << "A(int a)" << endl;_a = a;}~A(){cout << "~A()" << endl;}
private:int _a;
};typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){_array[_size] = data;_size++;}/*~Stack(){cout << "~Stack()" << endl;free(_array);_array = nullptr;_size = _capacity = 0;}*/
private:// 内置类型DataType* _array;int _capacity;int _size;// 自定义类型A _aa;
};void TestStack()
{Stack s;s.Push(1);s.Push(2);
}int main()
{TestStack();return 0;
}
四、拷贝构造
日期类拷贝:
#include<iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){_array[_size] = data;_size++;}~Stack(){cout << "~Stack()" << endl;free(_array);_array = nullptr;_size = _capacity = 0;}
private:// 内置类型DataType* _array;int _capacity;int _size;
};class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << "/" << endl;}
private://内置类型int _year;int _month;int _day;
};void func1(Date d)
{d.Print();
}int main()
{Date d1(2025,1,8);func1(d1);return 0;
}
栈拷贝:
#include<iostream>
using namespace std;
typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){_array[_size] = data;_size++;}~Stack(){cout << "~Stack()" << endl;free(_array);_array = nullptr;_size = _capacity = 0;}
private:// 内置类型DataType* _array;int _capacity;int _size;
};class Date
{
public:Date(int year, int month, int day){_year = year;_month = month;_day = day;}void Print(){cout << _year << "/" << _month << "/" << _day << "/" << endl;}
private://内置类型int _year;int _month;int _day;
};void func1(Date d)
{d.Print();
}void func2(Stack s)
{}int main()
{Date d1(2025,1,8);func1(d1);Stack s1;func2(s1);return 0;
}
解决方法:
void func2(Stack& s)
{//使用引用
}
拷贝构造函数
定义:只有单个形参,该形参是对本类类型对象的引用(一般常用const修饰),在用已存
特征1:
拷贝构造函数是构造函数的一个重载形式。
特征2:
拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用。
#include<iostream>
using namespace std;class Date
{
public:Date(int year, int month, int day){cout << "Date(Date& d)" << endl;_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(2025,1,8);Date d2(d1);return 0;
}
Date(Date d){//没有引用会引发无穷递归调用_year = d._year;_month = d._month;_day = d._day;}
#include<iostream>
using namespace std;typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}Stack(Stack& s){cout << "Stack(Stack& s)" << endl;// 深拷贝_array = (DataType*)malloc(sizeof(DataType) * s._capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}memcpy(_array, s._array, sizeof(DataType) * s._size);_size = s._size;_capacity = s._capacity;}void Push(DataType data){_array[_size] = data;_size++;}~Stack(){cout << "~Stack()" << endl;free(_array);_array = nullptr;_size = _capacity = 0;}
private:// 内置类型DataType* _array;int _capacity;int _size;
};void func2(Stack s)
{s.Push(1);
}int main()
{Stack s1;func2(s1);Stack s2(s1);return 0;
}
问题:
如果不写拷贝构造函数,系统会自动生成吗?
#include<iostream>
using namespace std;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;
};typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){cout << "Stack()" << endl;_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}void Push(DataType data){_array[_size] = data;_size++;}~Stack(){cout << "~Stack()" << endl;free(_array);_array = nullptr;_size = _capacity = 0;}
private:DataType* _array;int _capacity;int _size;
};int main()
{Date d1(2025, 1, 1);Date d2 = d1;Stack st1;Stack st2(st1);return 0;
}
特征3:
我们不写,编译默认生成的拷贝构造,跟之前的构造函数特性不一样
1、内置类型, 值拷贝
2、自定义的类型,调用他的拷贝
总结:Date不需要我们实现拷贝构造,默认生成就可以用
Stack需要我们自己实现深拷贝的拷贝构造,默认生成会出问题
MyQueue对于默认生成的几个函数非常受用,人生赢家
#include<iostream>
using namespace std;typedef int DataType;
class Stack
{
public:Stack(size_t capacity = 3){cout << "Stack()" << endl;_array = (DataType*)malloc(sizeof(DataType) * capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}_capacity = capacity;_size = 0;}Stack(const Stack& s){cout << "Stack(Stack& s)" << endl;// 深拷贝_array = (DataType*)malloc(sizeof(DataType) * s._capacity);if (NULL == _array){perror("malloc申请空间失败!!!");return;}memcpy(_array, s._array, sizeof(DataType) * s._size);_size = s._size;_capacity = s._capacity;}void Push(DataType data){_array[_size] = data;_size++;}~Stack(){cout << "~Stack()" << endl;free(_array);_array = nullptr;_size = _capacity = 0;}
private:DataType* _array;int _capacity;int _size;
};class MyQueue
{
private:Stack _pushst;Stack _popst;
};int main()
{MyQueue mq1;MyQueue mq2 = mq1;return 0;
}

注意:
Date(const Date& d){//一般情况都加上constcout << "Date(Date& d)" << endl;_year = d._year;_month = d._month;_day = d._day;}Date(const Date& d){cout << "Date(Date& d)" << endl;//若不小心写反了,很容易忽视这里的错误d._year = _year ;d._month = _month;d._day = _day;}
五、运算符重载
问题1:
日期对象如何比较大小?能否用 < .
简单的代码实现:
#include<iostream>
using namespace std;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;
};bool DateLess (const Date& x1,const Date& x2)
{if (x1._year < x2._year){return true;}else if (x1._year == x2._year && x1._month < x2._month){return true;}else if (x1._year == x2._year && x1._month == x2._month && x1._day < x2._day){return true;}else{return false;}
}int main()
{Date d1(2025, 1, 1);Date d2(2025, 1, 11);cout<<DateLess(d1, d2)<<endl;return 0;
}
#include<iostream>
using namespace std;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;
};bool operator<(const Date& x1, const Date& x2)
{if (x1._year < x2._year){return true;}else if (x1._year == x2._year && x1._month < x2._month){return true;}else if (x1._year == x2._year && x1._month == x2._month && x1._day < x2._day){return true;}else{return false;}
}int main()
{Date d1(2025, 1, 1);Date d2(2025, 1, 11);cout << (d1 < d2) << endl;cout << (operator<(d1, d2)) << endl;return 0;
}
写为成员函数:
// d1 < d2
// d1.operator<(d2)
//操作数顺序不能随便换
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;}}
运算符复用
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;}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;}}bool operator==(const Date& d){return _year == d._year&& _month == d._month&& _day == d._day;}// d1 <= d2bool operator<=(const Date& d){return *this < d || *this == d;}bool operator>(const Date& d){return !(*this <= d);}bool operator>=(const Date& d){return !(*this < d);}bool operator!=(const Date& d){return !(*this == d);}
}
实现日期+运算
#include<iostream>
using namespace std;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;}int GetMonthDay(int year, int month){int monthArray[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 monthArray[month];}//如果写成Date& operator+(int day)会发现Date ret = d1 + 50;中d1也会改变,所以该写成+=Date& operator+=(int day){_day += day;while (_day > GetMonthDay(_year, _month)){// 月进位_day -= GetMonthDay(_year, _month);++_month;// 月满了if (_month == 13){++_year;_month = 1;}}return *this;}Date operator+(int day) //出了作用域对象不在了不能用引用返回{Date tmp(*this);tmp += day;return tmp;//tmp._day += day;//while (tmp._day > GetMonthDay(tmp._year, tmp._month))//{// // 月进位// tmp._day -= GetMonthDay(tmp._year, tmp._month);// ++_month;// // 月满了// if (tmp._month == 13)// {// ++tmp._year;// tmp._month = 1;// }//}//return tmp;}private:// 内置类型int _year;int _month;int _day;
};int main()
{Date d1(2023, 7, 21);Date d2(2022, 8, 21);Date ret = d1 + 50;ret.Print();d1.Print();return 0;
}
总结
以上就是今天要讲的内容,本文仅仅简单介绍了c++的基础知识。
相关文章:

C++学习第五天
创作过程中难免有不足,若您发现本文内容有误,恳请不吝赐教。 提示:以下是本篇文章正文内容,下面案例可供参考 一、构造函数 问题1 关于编译器生成的默认成员函数,很多童鞋会有疑惑:不实现构造函数的情况下…...

openharmony标准系统方案之瑞芯微RK3568移植案例
标准系统方案之瑞芯微RK3568移植案例 本文章是基于瑞芯微RK3568芯片的DAYU200开发板,进行标准系统相关功能的移植,主要包括产品配置添加,内核启动、升级,音频ADM化,Camera,TP,LCD,…...
深入理解 SSH 端口转发:本地 vs 远程 vs 动态转发
🌟 简介 SSH 端口转发(SSH Port Forwarding)作为一种强大而灵活的技术,不仅可以帮助我们安全地访问远程服务,还能轻松突破网络限制。本文将带你深入了解 SSH 端口转发的原理、类型和实战应用。 🌈 目录 &a…...

postman请求参数化
postman界面介绍 一、使用环境变量(Environment Variables)进行参数化 1、在请求中使用环境变量 在请求的url、请求头(Headers)、请求体(Body)等部分都可以使用环境变量。 URL 部分示例 点击 Postman 界面右上角的 “眼睛” 图标(Environment Quick Look)打开环境管理…...
基于 WEB 开发的汽车养护系统设计与实现
标题:基于 WEB 开发的汽车养护系统设计与实现 内容:1.摘要 本文介绍了基于 WEB 开发的汽车养护系统的设计与实现。文章首先阐述了系统的背景和目的,即随着汽车保有量的增加,汽车养护需求日益增长,传统的汽车养护方式已经无法满足人们的需求&…...
Nginx正向代理配置
Nginx 正向代理默认只支持 http 协议,不支持 https 协议,需借助 "ngx_http_proxy_connect_module" 模块实现 https 正向代理,详情请参考: https://github.com/chobits/ngx_http_proxy_connect_module 安装Nginx某些模块…...

本地仓库管理之当前分支内的操作
以刚搭建好的git仓库为例,刚搭建完的仓库只有master分支,使用git branch查看当前的分支情况。 elfubuntu:~/work/example/hello$ git branch *所在分支为当前分支,即master分支 当前分支进行源码修改时简单流程图如下: 在当前分…...
《内网穿透:网络拓展与安全防护的平衡艺术》
一、引言:开启内网穿透的大门 在当今数字化浪潮席卷全球的时代,网络已成为人们生活和工作中不可或缺的一部分。我们日常使用的网络,如同一个庞大而复杂的生态系统,其中内网和外网犹如两个相互关联却又有所区别的世界。 想象一下…...
【python写个可以运行的2048小游戏】
写一个完整的2048小游戏在Python中是一个相对复杂的任务,因为它涉及到用户界面、事件处理、游戏逻辑等多个方面。为了简化这个过程,我们可以使用Python的图形库,比如pygame。下面是一个简单的2048游戏的实现。 首先,确保你已经安…...

【Flink系列】9. Flink容错机制
9. 容错机制 在Flink中,有一套完整的容错机制来保证故障后的恢复,其中最重要的就是检查点。 9.1 检查点(Checkpoint) 9.1.1 检查点的保存 1)周期性的触发保存 “随时存档”确实恢复起来方便,可是需要我…...
DETR论文阅读
1. 动机 传统的目标检测任务需要大量的人工先验知识,例如预定义的先验anchor,NMS后处理策略等。这些人工先验知识引入了很多人为因素,且较难处理。如果能够端到端到直接生成目标检测结果,将会使问题变得很优雅。 2. 主要贡献 提…...

关于vite+vue3+ts项目中env.d.ts 文件详解
env.d.ts 文件是 Vite 项目中用于定义全局类型声明的 TypeScript 文件。它帮助开发者向 TypeScript提供全局的类型提示,特别是在使用一些特定于 Vite 的功能时(如 import.meta.env)。以下是详细讲解及代码示例 文章目录 **1. env.d.ts 文件的…...

如何优化Elasticsearch大文档查询?
记录一次业务复杂场景下DSL优化的过程 背景 B端商城业务有一个场景就是客户可见的产品列表是需要N多闸口及各种其它逻辑组合过滤的,各种闸口数据及产品数据都是存储在ES的(有的是独立索引,有的是作为产品属性存储在产品文档上)。 在实际使用的过程中&a…...

Kotlin Bytedeco OpenCV 图像图像54 透视变换 图像矫正
Kotlin Bytedeco OpenCV 图像图像54 透视变换 图像矫正 1 添加依赖2 测试代码3 测试结果 在OpenCV中,仿射变换(Affine Transformation)和透视变换(Perspective Transformation)是两种常用的图像几何变换方法。 变换方…...

Linux中DataX使用第一期
简介 DataX 是阿里云 DataWorks数据集成 的开源版本,在阿里巴巴集团内被广泛使用的离线数据同步工具/平台。DataX 实现了包括 MySQL、Oracle、OceanBase、SqlServer、Postgre、HDFS、Hive、ADS、HBase、TableStore(OTS)、MaxCompute(ODPS)、Hologres、DRDS, databen…...

[Qt]事件-鼠标事件、键盘事件、定时器事件、窗口改变事件、事件分发器与事件过滤器
目录 前言:Qt与操作系统的关系 一、Qt事件 1.事件介绍 2.事件的表现形式 常见的Qt事件: 常见的事件描述: 3.事件的处理方式 处理鼠标进入和离开事件案例 控件添加到对象树底层原理 二、鼠标事件 1.鼠标按下和释放事件(单击&#x…...

关于机器学习的一份总结
在之前的文章中分别有详细的关于机器学习中某一学习算法的介绍,但缺少一个总体关于机器学习的总结,所以在这篇文中就是关于机器学习的一份总结。 在最近的日子中,人工智能日益火热起来,而机器学习是其中举足轻重的一部分…...

推荐一个开源的轻量级任务调度器!TaskScheduler!
大家好,我是麦鸽。 这次推荐一款轻量级的嵌入式任务调度器,目前已经有1.4K的star,这个项目比较轻量化,只有5个源文件,可以作为学习的一个开源项目。 核心文件 项目概述: 这是一个轻量级的协作式多任务处理&…...

【18】Word:明华中学-儿童医保❗
目录 题目 NO2 NO3 NO4 NO5 NO6 NO7 NO8 NO9 题目 NO2 布局→页面设置对话框→纸张方向:横向→纸张大小:A3 ;页面设置对话框:直接输入纸张大小的宽度和高度即可→页面设置对话框:上下左右边距→版式&…...
如何用selenium来链接并打开比特浏览器进行自动化操作(1)
前言 本文是该专栏的第76篇,后面会持续分享python爬虫干货知识,记得关注。 本文,笔者将基于“比特浏览器”,通过selenium来实现链接并打开比特浏览器,进行相关的“自动化”操作。 值得一提的是,在本专栏之前,笔者有详细介绍过“使用selenium或者pyppeteer(puppeteer)…...
内存分配函数malloc kmalloc vmalloc
内存分配函数malloc kmalloc vmalloc malloc实现步骤: 1)请求大小调整:首先,malloc 需要调整用户请求的大小,以适应内部数据结构(例如,可能需要存储额外的元数据)。通常,这包括对齐调整,确保分配的内存地址满足特定硬件要求(如对齐到8字节或16字节边界)。 2)空闲…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...
06 Deep learning神经网络编程基础 激活函数 --吴恩达
深度学习激活函数详解 一、核心作用 引入非线性:使神经网络可学习复杂模式控制输出范围:如Sigmoid将输出限制在(0,1)梯度传递:影响反向传播的稳定性二、常见类型及数学表达 Sigmoid σ ( x ) = 1 1 +...

vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...

Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...
管理学院权限管理系统开发总结
文章目录 🎓 管理学院权限管理系统开发总结 - 现代化Web应用实践之路📝 项目概述🏗️ 技术架构设计后端技术栈前端技术栈 💡 核心功能特性1. 用户管理模块2. 权限管理系统3. 统计报表功能4. 用户体验优化 🗄️ 数据库设…...

基于江科大stm32屏幕驱动,实现OLED多级菜单(动画效果),结构体链表实现(独创源码)
引言 在嵌入式系统中,用户界面的设计往往直接影响到用户体验。本文将以STM32微控制器和OLED显示屏为例,介绍如何实现一个多级菜单系统。该系统支持用户通过按键导航菜单,执行相应操作,并提供平滑的滚动动画效果。 本文设计了一个…...

从零开始了解数据采集(二十八)——制造业数字孪生
近年来,我国的工业领域正经历一场前所未有的数字化变革,从“双碳目标”到工业互联网平台的推广,国家政策和市场需求共同推动了制造业的升级。在这场变革中,数字孪生技术成为备受关注的关键工具,它不仅让企业“看见”设…...

DAY 45 超大力王爱学Python
来自超大力王的友情提示:在用tensordoard的时候一定一定要用绝对位置,例如:tensorboard --logdir"D:\代码\archive (1)\runs\cifar10_mlp_experiment_2" 不然读取不了数据 知识点回顾: tensorboard的发展历史和原理tens…...
起重机起升机构的安全装置有哪些?
起重机起升机构的安全装置是保障吊装作业安全的关键部件,主要用于防止超载、失控、断绳等危险情况。以下是常见的安全装置及其功能和原理: 一、超载保护装置(核心安全装置) 1. 起重量限制器 功能:实时监测起升载荷&a…...