【c++初阶】类和对象②默认成员函数以及运算符重载初识
目录
编辑
默认成员函数:
构造函数
构造函数的特性:
析构函数:
拷贝构造函数:
1. 拷贝构造函数是构造函数的一个重载形式。
2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用。
默认生成的拷贝构造:
1.内置类型完成值拷贝
2. 若未显式定义,编译器会生成默认的拷贝构造函数。
3.拷贝构造函数的典型引用场景
默认赋值运算符
c++运算符重载
赋值:赋值运算符的重载:
默认成员函数:
对于上篇文章中讲解中所使用的类,一般正常使用是没有问题的,但是如果我们在使用某些类的时候,,比如我们的日期类使用时,忘记或者没有进行初始化会发生什么样的问题呢:

现象是编译通过,但是成员变量都是随机值。 严重一点可能会崩溃。
为了解决这个问题,C++中引入了构造函数:
构造函数
是一个特殊的成员函数,名字与类名相同,创建类类型对象时由编译器自动调用,以保证 每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次。
构造函数的特性:
构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任 务并不是开空间创建对象,而是初始化对象。 其特征如下:
1. 函数名与类名相同。
2. 无返回值。
3. 对象实例化时编译器自动调用对应的构造函数。
4. 构造函数可以重载。
5. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦 用户显式定义编译器将不再生成。

两个默认构造函数的功能和Init函数的功能是一模一样的,但是构造函数可以默认调用:
如何调用带参数的构造函数呢:
在创建对象的时候自动调用,

没有参数调用的时候不可以在对象名字后面加上括号

因为无法和函数声明区分开。
编写某认构造的时候可以使用缺省参数,和无参调用构成重载但是不可以同时存在,无参调用时二者会产生歧义:
Date(int year = 2025, int mouth = 1, int day = 1)
{_year = year;_mouth = mouth;_day = day;
}
//写一个构造函数的重载://Date()
//{
// _year = 2025;
// _mouth = 1;
// _day = 1;
//}
通过上面的例子我们知道,如果我们不写构造函数,使用的时候也可以打印出值,不过是随机值,这就意味着在c++中如果我们不写构造函数应该是有构造函数的,接下来我们观察一个栈的实现类:
现象:队列没写构造函数但是调用了栈的构造函数,如果写一个int size正常应该是不初始化化,初始化的原因是编译器自己做了一些优化。所以这个行为是不确定的。
C语言将数据类型分为了内置类型和自定义类型,
内置类型:int char 指针等,所以Date* p是内置类型,因为是指针,指针的本质就是地址。
自定义类型:struct class enum等等。
某认生成构造函数:内置类型成员不做处理,自定义类型会去调用他的默认构造。
vs2022现象,当一个对象的成员变量中有自定义类型和内置类型的时候,都会去初始化,但是当只有内置类型的时候又不初始化,这是由于编译器的优化导致。
上述对于两种不同类型数据的区别对待使得学习c++这门语言有些冗余,于是在C++11中做了这样的补丁,对于成员变量允许这样操作:

但是,值得注意的是这里的几个成员变量在1这里依旧是声明,并没有因为初始化而变成定义
原因: 这在类中相当于还是图纸,只有当用这个类的类型实例化一个对象的时候才会开辟空间,这里的值理解成缺省值。编译器生成某认构造的时候就可以用了。
重点:无参的构造函数和全缺省的构造函数以及编译器自己生成的构造函数,都称为默认构造函数,并且默认构造函数只能有一个。 注意:无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数,都可以认为 是默认构造函数。也就是不传参的都是默认构造函数。三个函数不能同时存在,否则有歧义。
总结:
1.一般情况下,我们都要自己写构造函数
2.成员都是自定义类型,或者声明时给了缺省值,可以考虑让编译器自己去生成构造函数。
析构函数:
析构函数:与构造函数功能相反,析构函数不是完成对对象本身的销毁,局部对象销毁工作是由 编译器完成的。而对象在销毁时会自动调用析构函数,完成对象中资源的清理工作。
特性 析构函数是特殊的成员函数,其特征如下:
1. 析构函数名是在类名前加上字符 ~。
2. 无参数无返回值类型。
3. 一个类只能有一个析构函数。若未显式定义,系统会自动生成默认的析构函数。注意:析构 函数不能重载
4. 对象生命周期结束时,C++编译系统系统自动调用析构函数。
日期类实际上没有需要时释放的资源,可以看一下调用析构函数的过程:
~Date()
{cout << "data destory" << endl;
}
出了作用领域,,自动调用。

对于栈的释放资源,析构函数是必要的,内存泄漏不会报错。
~Stack()
{free(_a);_capacity = _top = 0;_a = nullptr;
}
对象的开辟和销毁是由系统来进行的
编译器 生成的默认析构函数,对自定类型成员调用它的析构函数。对于栈类,我们不写析构函数,不会自己销毁,因为编译器不敢。对内置类型不做处理,对自定义类型调用其析构函数。
拷贝构造函数:
传参本质就是一个拷贝。
对于日期类的传参拷贝:
void Test(Date d)
{d.Print();
}int main()
{Date d1;Test(d1);
这是值拷贝也就是浅拷贝
对于栈类的传参如果也使用值拷贝:
可能会出现对一块空间进行多次释放的问题。
c++规定,自定义类型的对象拷贝的时候,调用一个函数,这个函数叫做拷贝构造。
Date d2(d1) 使用d1初始化d2也是拷贝构造。
1. 拷贝构造函数是构造函数的一个重载形式。
日期类的拷贝构造:
Date(Date& d)
{_year =d._year;_mouth = d._mouth;_day = d._day;
}
2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报错, 因为会引发无穷递归调用。
调用拷贝构造如果是传值传参的话又会引起拷贝构造。
所以会用传指针和传引用的方式。
c++规定自定义类型对象传参拷贝,必须经过拷贝构造。可以这么理解
但是引用传参和指针传参不会发生拷贝构造函数的调用。
关于栈类的拷贝,浅拷贝可能会引起析构的时候一块空间释放两次的问题,所以栈类一般定义为深拷贝:
Stack(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;
}
对于队列类,我们没有写拷贝构造函数,自己调用了拷贝构造:

默认生成的拷贝构造:
1.内置类型完成值拷贝
自定义类型会调用这个成员的拷贝构造。(比如栈这种类型需要我们自己写一个深拷贝,浅拷贝可能会出问题)
写拷贝构造的时候最好带上const修饰,否则会出现反向拷贝的情况。
2. 若未显式定义,编译器会生成默认的拷贝构造函数。
默认的拷贝构造函数对象按内存存储按 字节序完成拷贝,这种拷贝叫做浅拷贝,或者值拷贝。
注意:在编译器生成的默认拷贝构造函数中,内置类型是按照字节方式直接拷贝的,而自定 义类型是调用其拷贝构造函数完成拷贝的。
3.拷贝构造函数的典型引用场景
①使用已经存在的对象创建新对象
②函数参数类型为类 类型对象
③函数返回值类型为类类型对象
默认赋值运算符
对于“=”,也就是赋值运算符的运算,如果我们不显示实现编译器也会生成一个默认的。跟拷贝构造的行为类似,内置类型完成值拷贝,自定义类型调用它的赋值。stake类涉及空间开辟的情况,需要自己实现完成深层次拷贝,介绍赋值运算符之前,我们先要了解c++中的运算符重载。
c++运算符重载
对于+ - * /这样运算符内置类型可以直接使用,但是自定义类型不可以直接使用
int a = 1;
int b = 2;
c = a+ b;
但是 Date d1 Date d2
d1 == d2这样就不可以直接使用。
对于内置类型来说,编译器知道其类型的含义就可以进行比较,直接就转换成指令了
但是对于自定义类型来说,编译器不知道要按照什么样的规则来进行比较。
C++为了增强代码的可读性引入了运算符重载,运算符重载是具有特殊函数名的函数,也具有其 返回值类型,函数名字以及参数列表,其返回值类型与参数列表与普通的函数类似。
函数名字为:关键字operator后面接需要重载的运算符符号。
函数原型:返回值类型 operator操作符(参数列表)
注意:
不能通过连接其他符号来创建新的操作符:比如operator@
重载操作符必须有一个类类型参数
用于内置类型的运算符,其含义不能改变,例如:内置的整型+,不 能改变其含义
作为类成员函数重载时,其形参看起来比操作数数目少1,因为成员函数的第一个参数为隐 藏的this
那么日期类的比较就可以这样来写,关于日期的比较不像自定义类型那些谁大就大,而是有一个比较逻辑,编译器是不能确定我们自己定义的类的比较逻辑的,无法统一所以就无法比较。
bool operator>(const Date& d1, const Date& d2)
{if (d1._year > d2._year){return true;}if (d1._year == d2._year && d1._mouth > d2._mouth){return true;}if (d1._year == d2._year && d1._mouth == d2._mouth && d1._day > d2._day){return true;}return false;}

此时的c++可以支持这样写;
此时的使用就和我们的内置类型使用运算符感觉没有差异了。
当我们将这个函数的实现放在类里面就会报错:

因为还有一个隐藏的this指针,参数要和操作数匹配,所以这样修改:
bool operator==( const Date& d2)
{return _year == d2._year&& _mouth == d2._mouth&& _day == d2._day;
}
bool operator>( const Date& d2)
{if (_year > d2._year){return true;}if (_year == d2._year && _mouth > d2._mouth){return true;}if (_year == d2._year && _mouth == d2._mouth && _day > d2._day){return true;}return false;}
调用时这样调用:
d1.operator>(d2);
可以重载那些运算符,主要看这个运算有没有意义,有意义就可以实现,没有意义就不要实现。
赋值:赋值运算符的重载:
两个已经存在的对象进行拷贝。而拷贝构造是一个已经存在的对象去拷贝初始化另外一个对象。
Date& operator=(const Date&d)
{if (this != &d){_year = d._year;_mouth = d._mouth;_day = d._day;}return *this;}
赋值函数是一个默认构造函数,operate= 我们不写编译器会默认生成一个。行为跟拷贝构造类型,对内置类型完成值拷贝,对自定义类型完成他的赋值。date可以不写,myqueque1不写,栈要写,完成深度拷贝。
以上就是c++中的默认成员函数以及支持的默认行为。下一篇文章将介绍c++中的运算符重载
相关文章:
【c++初阶】类和对象②默认成员函数以及运算符重载初识
目录 编辑 默认成员函数: 构造函数 构造函数的特性: 析构函数: 拷贝构造函数: 1. 拷贝构造函数是构造函数的一个重载形式。 2. 拷贝构造函数的参数只有一个且必须是类类型对象的引用,使用传值方式编译器直接报…...
【做一个微信小程序】校园地图页面实现
前言 上一个教程我们实现了小程序的一些的功能,有背景渐变色,发布功能有的呢,已支持图片上传功能,表情和投票功能开发中(请期待)。下面是一个更高级的微信小程序实现,包含以下功能:…...
成熟开发者需具备的能力
精业务 • 指深入理解和熟悉所开发软件的业务逻辑和需求。 • 开发者需要明确软件要解决的问题、面向的用户群体以及核心功能等。 • 精业务有助于开发者更好地设计系统架构、编写符合业务需求的代码,并能根据业务变化灵活调整开发计划。 懂原理 • 指掌握编程的基…...
计算机毕业设计--基于深度学习技术(Yolov11、v8、v7、v5)算法的高效人脸检测模型设计与实现(含Github代码+Web端在线体验界面)
基于深度学习技术(Yolov11、v8、v7、v5)算法的高效人脸检测模型 Yolo算法应用之《基于Yolo的花卉识别算法模型设计》,请参考这篇CSDN作品👇 计算机毕业设计–基于深度学习技术(Yolov11、v8、v7、v5)算法的…...
力扣做题记录 (二叉树)
二叉树 打算先来了解二叉树基础,都是简单题,目的是熟悉代码格式和解题基础思路。 1、二叉树最大深度 二叉树最大深度 方法一、深度搜索 直接用原函数做递归,比较简单 /*** Definition for a binary tree node.* struct TreeNode {* …...
机试刷题_字符串的排列【python】
题目:字符串的排列 from os import dup # # 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可 # # # param str string字符串 # return string字符串一维数组 # class Solution:def backtrack(self,res,state,choi…...
百度智能云—千帆 ModelBuilder API的简单调用(Java)
百度简介 百度(Baidu)是拥有强大互联网基础的领先AI公司。百度愿景是:成为最懂用户,并能帮助人们成长的全球顶级高科技公司。 “百度”二字,来自于八百年前南宋词人辛弃疾的一句词:众里寻他千百度。这句话…...
unity学习43:子状态机 sub-state machine
目录 1sub-state machine子状态机 1.1 创建 sub-state machine 1.2 sub-state machine 内容 1.3 子状态机的应用 2 子状态机不同于blend tree的嵌套 3 应用例子:若角色拿不同武器的动画设计,可以使用2种方法 3.1 在1个图层layer里,使用…...
Qt MainWindow
文章目录 0. 概述1. 菜单栏 QMenuBar1.1 例子1,使用图形化界面1.2 例子2,使用代码创建1.3 例子3,添加快捷键1.4 例子4,添加子菜单1.5 例子5,添加分割线和图标1.6 内存泄漏问题 2. 工具栏 QToolBar2.1 例子1,…...
GDB QUICK REFERENCE (GDB 快速参考手册)
GDB QUICK REFERENCE {GDB 快速参考手册} References GDB QUICK REFERENCE GDB Version 4 https://users.ece.utexas.edu/~adnan/gdb-refcard.pdf 查看方式:在新标签页中打开图片 References [1] Yongqiang Cheng, https://yongqiang.blog.csdn.net/ [2] gdb-refc…...
【数据结构】 栈和队列
在计算机科学的世界里,数据结构是构建高效算法的基础。栈(Stack)和队列(Queue)作为两种基本且重要的数据结构,在软件开发、算法设计等众多领域都有着广泛的应用。今天,我们就来深入探讨一下栈和…...
AI视频创作教程:如何用AI让古画动起来。
事情缘由: 如果是简单的图,找原图直接写提示词即可。 如果碰到多人多活动的图,直接出的效果会很不好,那么该怎么做呢? 图片分模块 首先,复杂部分的图,把长图分多个模块。 比如这张图࿰…...
撕碎QT面具(1):Tab Widget转到某个Tab页
笔者未系统学过C语法,仅有Java基础,具体写法仿照于大模型以及其它博客。自我感觉,如果会一门对象语言,没必要先刻意学C,因为自己具有对象语言的基础,等需要用什么再学也不迟。毕竟不是专门学C去搞算法。 1…...
DeepSeek24小时写作机器人,持续创作高质量文案
内容创作已成为企业、自媒体和创作者的核心竞争力。面对海量的内容需求,人工创作效率低、成本高、质量参差不齐等问题日益凸显。如何在有限时间内产出高质量内容?DeepSeek写作机器人,一款24小时持续创作的智能工具,为企业和个人提…...
npm安装依赖(npm install)时遇到认证错误的解决方案
问题描述 在使用 npm install 安装依赖时遇到以下错误: npm error code E401 npm error Incorrect or missing password.解决方案 方案一:使用淘宝(或其它国内公共)镜像(如果已经是淘宝镜像跳过此步) 设…...
SpringBoot+微信小程序+数据可视化的宠物到家喂宠服务(程序+论文+讲解+安装+调试+售后等)
感兴趣的可以先收藏起来,还有大家在毕设选题,项目以及论文编写等相关问题都可以给我留言咨询,我会一一回复,希望帮助更多的人。 系统介绍 在经济高速发展、物质生活极大丰富的当下,人们的精神需求愈发凸显࿰…...
免费大模型网站
腾讯元宝 腾讯元宝 秘塔搜索 秘塔搜索 超算互联网 超算互联网回答速度很慢 Chatbot Arena Chatbot Arena 大模型竞技场。...
OpenCV的主要模块
OpenCV的模块...
使用 Python 爬虫和 FFmpeg 爬取 B 站高清视频
以下是一个完整的 Python 爬虫代码示例,用于爬取 B 站视频并使用 FFmpeg 合成高清视频。 1. 准备工作 确保安装了以下 Python 库和工具: bash复制 pip install requests moviepy2. 爬取视频和音频文件 B 站的视频和音频文件通常是分开存储的&#x…...
Retrieval-Augmented Generation for LargeLanguage Models: A Survey
标题:Retrieval-Augmented Generation for Large Language Models: A Survey 作者:Yunfan Gaoa , Yun Xiongb , Xinyu Gaob , Kangxiang Jiab , Jinliu Panb , Yuxi Bic , Yi Daia , Jiawei Suna , Meng Wangc , and Haofen Wang 1. By referencing ext…...
Android Wi-Fi 连接失败日志分析
1. Android wifi 关键日志总结 (1) Wi-Fi 断开 (CTRL-EVENT-DISCONNECTED reason3) 日志相关部分: 06-05 10:48:40.987 943 943 I wpa_supplicant: wlan0: CTRL-EVENT-DISCONNECTED bssid44:9b:c1:57:a8:90 reason3 locally_generated1解析: CTR…...
Python:操作 Excel 折叠
💖亲爱的技术爱好者们,热烈欢迎来到 Kant2048 的博客!我是 Thomas Kant,很开心能在CSDN上与你们相遇~💖 本博客的精华专栏: 【自动化测试】 【测试经验】 【人工智能】 【Python】 Python 操作 Excel 系列 读取单元格数据按行写入设置行高和列宽自动调整行高和列宽水平…...
1.3 VSCode安装与环境配置
进入网址Visual Studio Code - Code Editing. Redefined下载.deb文件,然后打开终端,进入下载文件夹,键入命令 sudo dpkg -i code_1.100.3-1748872405_amd64.deb 在终端键入命令code即启动vscode 需要安装插件列表 1.Chinese简化 2.ros …...
如何将联系人从 iPhone 转移到 Android
从 iPhone 换到 Android 手机时,你可能需要保留重要的数据,例如通讯录。好在,将通讯录从 iPhone 转移到 Android 手机非常简单,你可以从本文中学习 6 种可靠的方法,确保随时保持连接,不错过任何信息。 第 1…...
Android Bitmap治理全解析:从加载优化到泄漏防控的全生命周期管理
引言 Bitmap(位图)是Android应用内存占用的“头号杀手”。一张1080P(1920x1080)的图片以ARGB_8888格式加载时,内存占用高达8MB(192010804字节)。据统计,超过60%的应用OOM崩溃与Bitm…...
【Oracle】分区表
个人主页:Guiat 归属专栏:Oracle 文章目录 1. 分区表基础概述1.1 分区表的概念与优势1.2 分区类型概览1.3 分区表的工作原理 2. 范围分区 (RANGE Partitioning)2.1 基础范围分区2.1.1 按日期范围分区2.1.2 按数值范围分区 2.2 间隔分区 (INTERVAL Partit…...
Mysql8 忘记密码重置,以及问题解决
1.使用免密登录 找到配置MySQL文件,我的文件路径是/etc/mysql/my.cnf,有的人的是/etc/mysql/mysql.cnf 在里最后加入 skip-grant-tables重启MySQL服务 service mysql restartShutting down MySQL… SUCCESS! Starting MySQL… SUCCESS! 重启成功 2.登…...
NPOI Excel用OLE对象的形式插入文件附件以及插入图片
static void Main(string[] args) {XlsWithObjData();Console.WriteLine("输出完成"); }static void XlsWithObjData() {// 创建工作簿和单元格,只有HSSFWorkbook,XSSFWorkbook不可以HSSFWorkbook workbook new HSSFWorkbook();HSSFSheet sheet (HSSFSheet)workboo…...
【Elasticsearch】Elasticsearch 在大数据生态圈的地位 实践经验
Elasticsearch 在大数据生态圈的地位 & 实践经验 1.Elasticsearch 的优势1.1 Elasticsearch 解决的核心问题1.1.1 传统方案的短板1.1.2 Elasticsearch 的解决方案 1.2 与大数据组件的对比优势1.3 关键优势技术支撑1.4 Elasticsearch 的竞品1.4.1 全文搜索领域1.4.2 日志分析…...
深度学习之模型压缩三驾马车:模型剪枝、模型量化、知识蒸馏
一、引言 在深度学习中,我们训练出的神经网络往往非常庞大(比如像 ResNet、YOLOv8、Vision Transformer),虽然精度很高,但“太重”了,运行起来很慢,占用内存大,不适合部署到手机、摄…...

