当前位置: 首页 > news >正文

类和对象(C++)——默认成员函数,构造函数,析构函数

1. 类的默认成员函数

默认成员函数就是用户没有显式实现,编译器会⾃动⽣成的成员函数称为默认成员函数。⼀个类,不写的情况下编译器会默认生成以下6个默认成员函数,需要注意的是这6个中最重要的是前4个,最后两个取地址重载,后面小编会大概讲解一下,了解⼀下。其次就是C++11以后还会增加两个默认成员函数, 移动构造和移动赋值,这个小编后面再讲解。默认成员函数比较复杂,从两个⽅⾯去考虑:

a)我们不写时,编译器默认⽣成的函数行为是什么,是否满⾜我们的需求。

b)编译器默认⽣成的函数不满⾜我们的需求,需要自己实现,如何自己实现?

2. 构造函数

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象(我们常使用的局部对象是栈帧创建时,空间就开好了),⽽是对象实例化时初始化对象。构造函数的本质是要替代我们以前Stack和Date类中写的Init函数的功能,构造函数⾃动调⽤的特点就完美的替代的了Init。

构造函数的特点:

a)函数名与类名相同。

b)⽆返回值。(返回值啥都不需要给,也不需要写void,不要纠结,C++规定如此)

c)对象实例化时系统会⾃动调⽤对应的构造函数。

例如:

class Date
{
public:// 1.⽆参构造函数Date(){_year = 1;_month = 1;_day = 1;}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;// 调⽤默认构造函数d1.Print();return 0;
}

当对d1进行实例化时,会调用构造函数Date进行初始化。

d)构造函数可以重载。

例如:

#include<iostream>
using namespace std;class Date
{
public:// 1.⽆参构造函数Date(){_year = 1;_month = 1;_day = 1;}//2.带参构造函数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;
};
int main()
{Date d1;Date d2(2024,12,13);d1.Print();d2.Print();return 0;
}

结果:

Date构造函数,参数的个数,类型不同,构成函数重载。

e)如果类中没有显式定义构造函数,则C++编译器会自动⽣成⼀个⽆参的默认构造函数,⼀旦⽤户显式定义编译器将不再生成。

#include<iostream>
using namespace std;class Date
{
public:void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};
int main()
{Date d1;Date d2;// 调⽤默认构造函数d1.Print();d2.Print();return 0;
}

当自己没有定义构造函数时,编译器就会自动⽣成⼀个无参的默认构造函数,所以给的值就是随机值了。

f)无参构造函数、全缺省构造函数、我们不写构造时编译器默认生成的构造函数,都叫做默认构造函数。但是这三个函数有且只有⼀个存在,不能同时存在。无参构造函数和全缺省构造函数虽然构成函数重载,但是调⽤时会存在歧义。注意很多小伙伴会认为默认构造函数是编译器默认生成那个叫默认构造,实际上无参构造函数、全缺省构造函数也是默认构造,简而言之就是不传实参就可以调用的构造就叫默认构造。

例如:

无参构造函数和全缺省构造函数虽然构成函数重载,但是调⽤时会存在歧义

#include<iostream>
using namespace std;class Date
{
public:1.⽆参构造函数Date(){_year = 1;_month = 1;_day = 1;}//3.全缺省构造函数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;
};
int main()
{Date d1;Date d2;// 调⽤默认构造函数d1.Print();d2.Print();return 0;
}

g)我们不写,编译器默认生成的构造,对内置类型成员变量(如:int,float,double,int*)的初始化没有要求,也就是说是是否初始化是不确定的,看编译器。对于自定义类型成员(如:struct)变量,要求调⽤这个成员变量的默认构造函数初始化。如果这个成员变量,没有默认构造函数,那么就会报错,我们要初始化这个成员变量,需要⽤初始化列表才能解决,初始化列表,小编后面章节再讲解。

例如:

这里用之前“用栈实现队列“举例子

typedef int STDataType;
class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc fail");return;}_capacity = n;_top = 0;}
private:STDataType* _a;size_t _capacity;size_t _top;
};
// 两个Stack实现队列class MyQueue
{
public://编译器默认⽣成MyQueue的构造函数调⽤了Stack的构造,完成了两个成员的初始化
private:Stack pushst;Stack popst;
};int main()
{MyQueue mq;return 0;
}

这里在实例化mq对象时,就会去调用stack的构造函数,进行初始化。

3. 析构函数

析构函数与构造函数功能相反,析构函数不是完成对对象本⾝的销毁,比如局部对象是存在栈帧的,函数结束栈帧销毁,他就释放了,不需要我们管,C++规定对象在销毁时会⾃动调⽤析构函数,完成对象中资源的清理释放⼯作。析构函数的功能类⽐我们之前Stack实现的Destroy功能,⽽像Date没有Destroy,其实就是没有资源需要释放(例如malloc堆上开辟的空间就需要释放),所以严格说Date是不需要析构函数的。

析构函数的特点:

a)析构函数名是在类名前加上字符~。

b)⽆参数⽆返回值。(这⾥跟构造类似,也不需要加void)

c)⼀个类只能有⼀个析构函数。若未显式定义,系统会⾃动⽣成默认的析构函数。

d)对象⽣命周期结束时,系统会⾃动调⽤析构函数。

f)跟构造函数类似,我们不写,编译器自动生成的析构函数对内置类型成员不做处理,自定类型成员会调⽤他的析构函数。

typedef int STDataType;
class Stack
{
public:Stack(int n = 4){_a = (STDataType*)malloc(sizeof(STDataType) * n);if (nullptr == _a){perror("malloc fail");return;}_capacity = n;_top = 0;}~Stack(){cout << "~Stack()" << endl;free(_a);_a = nullptr;_top = _capacity = 0;}
private:STDataType* _a;size_t _capacity;size_t _top;
};
// 两个Stack实现队列class MyQueue
{
public://编译器默认⽣成MyQueue的构造函数调⽤了Stack的构造,完成了两个成员的初始化
private:Stack pushst;Stack popst;
};int main()
{Stack st;MyQueue mq;return 0;
}

结果:

这里生命周期结束时,就会调用析构函数,这里实例化对象st,调用了一次析构函数,实例化对象mq(自定义类型)时,中的两个pushst,popst,会去调用Stack中中的析构函数。

g)如果类中没有申请资源时,析构函数可以不写,直接使⽤编译器⽣成的默认析构函数,如Date;如果默认生成的析构就可以⽤,也就不需要显示写析构,如MyQueue;但是有资源申请时,⼀定要自己写析构,否则会造成资源泄漏,如Stack。

h)⼀个局部域的多个对象,C++规定后定义的先析构。

也就是上面这段代码中的mq中的pushst,和popst会先析构,再对st进行析构。

示例:对比⼀下⽤C++和C实现的Stack解决之前括号匹配问题isValid(小编前面文章有详细讲解,这里就不详细讲逻辑),我们发现有了构造函数和析构函数确实⽅便了很多,不会再忘记调⽤Init和Destory函数了,也⽅便了不少。

//C++版
bool isValid(const char* s) {Stack st;while (*s){if (*s == '[' || *s == '(' || *s == '{'){st.Push(*s);}else{// 右括号⽐左括号多,数量匹配问题if (st.Empty()){return false;}// 栈⾥⾯取左括号char top = st.Top();st.Pop();// 顺序不匹配if ((*s == ']' && top != '[')|| (*s == '}' && top != '{')|| (*s == ')' && top != '(')){return false;}}++s;}// 栈为空,返回真,说明数量都匹配左括号多,右括号少匹配问题return st.Empty();
}// ⽤之前C版本Stack实现
bool isValid(const char* s) {ST st;STInit(&st);while (*s){// 左括号⼊栈if (*s == '(' || *s == '[' || *s == '{'){STPush(&st, *s);}else // 右括号取栈顶左括号尝试匹配{if (STEmpty(&st)){STDestroy(&st);return false;}char top = STTop(&st);STPop(&st);// 不匹配if ((top == '(' && *s != ')')|| (top == '{' && *s != '}')|| (top == '[' && *s != ']')){STDestroy(&st);return false;}}++s;}//栈不为空,说明左括号⽐右括号多,数量不匹配bool ret = STEmpty(&st);STDestroy(&st);return ret;
}

相关文章:

类和对象(C++)——默认成员函数,构造函数,析构函数

1. 类的默认成员函数 默认成员函数就是用户没有显式实现&#xff0c;编译器会⾃动⽣成的成员函数称为默认成员函数。⼀个类&#xff0c;不写的情况下编译器会默认生成以下6个默认成员函数&#xff0c;需要注意的是这6个中最重要的是前4个&#xff0c;最后两个取地址重载&#…...

深入理解 Vue v-model 原理与应用

一、引言 在 Vue.js 开发中,v-model是一个非常重要且强大的指令。它为开发者在处理表单输入和数据双向绑定等场景中提供了极大的便利。无论是新手还是有经验的开发者,深入理解v-model对于高效地构建 Vue 应用至关重要。本文将对v-model进行深入剖析,从其基本原理、使用方式…...

内网域环境、工作组、局域网等探针方案

1. 信息收集 1.1 网络收集 了解当前服务器的计算机基本信息&#xff0c;为后续判断服务器角色&#xff0c;网络环境做准备 systeminfo 详细信息 net start 启动服务 tasklist 进程列表 schtasks 计划任务&#xff08;受权限影响&#xff09; 了解当前服务器的网络接口信息…...

uniapp—android原生插件开发(3Android真机调试)

本篇文章从实战角度出发&#xff0c;将UniApp集成新大陆PDA设备RFID的全过程分为四部曲&#xff0c;涵盖环境搭建、插件开发、AAR打包、项目引入和功能调试。通过这份教程&#xff0c;轻松应对安卓原生插件开发与打包需求&#xff01; 一、打包uniapp资源包&#xff1a; 打包…...

goframe开发一个企业网站 统一返回响应码 18

响应码的logic package returncodeimport ("context""gf_new_web/internal/service""github.com/gogf/gf/v2/errors/gcode""github.com/gogf/gf/v2/frame/g" )type sReturncode struct { }var (insReturncode sReturncode{}…...

基于STM32的智能门禁系统设计

引言 本项目基于STM32微控制器设计了一个智能门禁系统&#xff0c;通过集成多个传感器模块和控制设备&#xff0c;实现对门禁系统的自动化管理与控制。该系统能够通过RFID卡、密码输入、以及指纹传感器等多种方式对进出人员进行验证&#xff0c;并结合LCD显示屏提供实时信息反…...

Python学习从0到1 day28 Python 高阶技巧 ⑧ 递归

那就祝我们爬不同的山&#xff0c;还能回到同一条路上&#xff0c;不是时时见面&#xff0c;但是时时惦记之人 —— 24.11.13 递归 1.什么是递归 递归在编程中是一种非常重要的算法 递归&#xff1a;即方法(函数)自己调用自己的一种特殊编程写法 函数调用自己&#xff0c;即…...

知识见闻 - 苹果手机拨号键长按

苹果手机&#xff08;iPhone&#xff09;在拨号界面长按按键时有一些特定的功能。以下是iPhone拨号键盘上长按按键的主要功能&#xff1a; 数字键 0 - 长按可输入""号&#xff0c;用于国际电话拨号 - 这是最常用的长按功能之一&#xff0c;方便用户拨打国际电话 星号…...

在 KubeVirt 中使用 GPU Operator

在 KubeVirt 中使用 GPU Operator 基于最新的GPU Operator版本24.9.0。 原文链接&#xff1a;GPU Operator with KubeVirt — NVIDIA GPU Operator 24.9.0 documentation 1. 简介 KubeVirt 是 Kubernetes 的一个虚拟机管理插件&#xff0c;允许您在 Kubernetes 集群中运行和…...

安慰剂检验Stata代码(全套代码、示例数据及参考文献)

数据简介&#xff1a;随着因果推断方法在实证研究中的使用比例不断提升&#xff0c;越来越多的文章进行安慰剂检验。其检验基本原理与医学中的安慰剂类似&#xff0c;即使用假的政策发生时间或实验组进行分析&#xff0c;以检验能否得到政策效应。如果依然得到了政策效应&#…...

DAY6 线程

作业1&#xff1a; 多线程实现文件拷贝&#xff0c;线程1拷贝一半&#xff0c;线程2拷贝另一半&#xff0c;主线程回收子线程资源。 代码&#xff1a; #include <myhead.h> sem_t sem1; void *copy1()//子线程1函数 拷贝前一半内容 {int fd1open("./1.txt",O…...

基于STM32的智能门锁系统设计思路:蓝牙、RFID等技术

一、项目概述 在现代家居安全领域&#xff0c;传统门锁因其安全性不足、开锁方式单一等问题&#xff0c;已逐渐无法满足用户的需求。传统机械锁容易被撬开、复制钥匙&#xff0c;同时开锁方式仅限于物理钥匙&#xff0c;给用户带来不便。因此&#xff0c;本文旨在设计并开发一…...

AndroidStudio-广播

一、广播的本质 广播是一种数据传输方式 二、Android 中的广播 发送一条广播&#xff0c;可以被不同的广播接收者所接收&#xff0c;广播接收者收到广播之后&#xff0c;再进行逻辑处理。 三、收发标准广播 广播的收发过程分为三个步骤&#xff1a; 1.发送标准广播 2.定义…...

基于表格滚动截屏(表格全部展开,没有滚动条)

import html2canvasPro from html2canvas // 截图&#xff0c;平辅表格 async function resetAgSize() {const allColumns gridApi.value.getColumns()let totalColumnWidth 0let totalColumnHeight 0// 遍历每一个行节点gridApi.value.forEachNode((rowNode) > {totalCo…...

洛谷P1255

P1255 数楼梯 - 洛谷 | 计算机科学教育新生态 数楼梯 题目描述 楼梯有 N 阶&#xff0c;上楼可以一步上一阶&#xff0c;也可以一步上二阶。 编一个程序&#xff0c;计算共有多少种不同的走法。 输入格式 一个数字&#xff0c;楼梯数。 输出格式 输出走的方式总数。 样…...

vue3设置第三方组件 样式::v-deep

在Vue 3中&#xff0c;使用了Composition API的组件可以通过<style>标签内部的::v-deep选择器来深入作用于第三方组件的样式。::v-deep是一个 Scoped CSS 的“深度选择器”&#xff0c;可以穿透组件边界&#xff0c;影响子组件的样式。比如我想修改el-date-picker的颜色边…...

JAVA学习日记(十四)集合进阶

一、单列集合Collection List系列集合特点&#xff1a;添加的元素是有序&#xff08;存和取的顺序一致&#xff09;、可重复、有索引 Set系列集合特点&#xff1a;添加的元素是无序&#xff08;存和取的顺序有可能不一致&#xff09;、不重复、无索引 Collection是所有单列集合…...

mysql全量与增量备份

binlog日志&#xff1a; 从上一次全量备份到下一次全量备份直接产生的数据。 一、全备和增量备份介绍 1、全量备份&#xff1a; 备份所有数据库或只备份一个数据库&#xff0c;全量备份之后&#xff0c;全量备份之前的binlog日志就没用了&#xff0c;一般生产环境会保留3-7天…...

“非法”操控lambda(python)

能过python解释器关卡即是合法脚本代码&#xff0c;偶尔的“违规”操控也是一种唯美。 (笔记模板由python脚本于2024年11月13日 11:18:21创建&#xff0c;本篇笔记适合熟悉python的lambda操控的coder翻阅) 【学习的细节是欢悦的历程】 Python 官网&#xff1a;https://www.pyth…...

UDP协议和TCP协议之间有什么具体区别?

UDP&#xff08;User Datagram Protocol&#xff09;和TCP&#xff08;Transmission Control Protocol&#xff09;是两种常见的网络传输协议&#xff0c;它们在数据传输中有着显著的区别和适用场景。理解它们的区别对于网络工程师、软件开发人员以及网络安全专家都是至关重要的…...

论文5—《基于改进YOLOv5s的轻量化金银花识别方法》文献阅读分析报告

论文报告&#xff1a;基于改进YOLOv5s的轻量化金银花识别方法 论文报告文档 基于改进YOLOv5s的轻量化金银花识别方法 论文报告文档摘要国内外研究现状国内研究现状国外研究现状 研究目的研究问题使用的研究方法试验研究结果文献结论创新点和对现有研究的贡献1. 目标检测技术2. …...

快手直播间采集教程,快手引流,快手截流,截流工具,直播间截流,快手直播间采集,获客系统,获客软件

功能&#xff1a; 1.输入快手直播间链接可一键监控直播间 2.可采集新进直播间的人 3.可采集直播间所有动作&#xff0c;包含&#xff1a;发弹幕的人和内容、送礼物的人和送的礼物、点亮爱心的人 4.可一键导出新进直播间的快手ID 5.可一键导出直播间动作列表&#xff0c;也可以筛…...

探索MoviePy:Python视频编辑的瑞士军刀

文章目录 &#x1f3ac; 探索MoviePy&#xff1a;Python视频编辑的瑞士军刀第一部分&#xff1a;背景介绍第二部分&#xff1a;MoviePy是什么&#xff1f;第三部分&#xff1a;如何安装MoviePy&#xff1f;第四部分&#xff1a;MoviePy的基本函数使用方法1. 视频剪辑2. 视频拼接…...

mysql 实现分库分表之 --- 基于 MyCAT 的分片策略详解

引言 在我们日常工作的项目中&#xff0c;特别是面向 C 端用户的产品&#xff0c;随着业务量的逐步扩大&#xff0c;数据量也呈指数级增长。为了应对日益增长的数据库压力&#xff0c;数据库优化已成为项目中不可或缺的一环&#xff0c;而分库分表则是海量数据优化方案中的重要…...

Opencascade基础教程(14): 一个模型显示问题

如果显示模型时出现如图情况&#xff0c;正对屏幕的平面特别亮&#xff0c;只需要设置材质为非金属就行。 //创建box并显示TopoDS_Shape aShape BRepPrimAPI_MakeBox(100, 100, 100);Handle(AIS_Shape) aisShpae new AIS_Shape(aShape);aisShpae->SetDisplayMode(AIS_Shad…...

ISP——你可以从这里起步(二)

接上一篇&#xff0c;上一篇是原理篇&#xff0c;这一篇是实战篇&#xff0c;为了实现下面框图中的不完美ISP。 第一章 做一张RAW图自己用 不是所有的人都能获得raw图&#xff0c;即使获得了raw图也需要对应的sensor参数才能把它用起来&#xff0c;所以我找了一条野路子可以把…...

Qt / Qt Quick程序打包的一些坑 (四)

【写在前面】 打包方法见 Qt / Qt Quick程序打包的方法。 这里是再次记录一些坑。 【正文开始】 直接进入正题&#xff1a; 在 Qt5 中&#xff0c;如果我们的 Qml 中使用了【Qt Shapes】模块&#xff0c;那么在打包的时候&#xff0c;会缺少Qt5QuickShapes.dll。 然后&#xff…...

《传统视觉算法在视觉算法中的地位及应用场景

一、引言 在计算机视觉领域的发展历程中&#xff0c;传统视觉算法扮演了至关重要的角色。尽管近年来深度学习算法在视觉任务中取得了巨大的成功&#xff0c;但传统视觉算法依然具有不可替代的地位。传统视觉算法通常基于数学模型和手工设计的特征&#xff0c;具有计算效率高、…...

老老实实干一辈子程序员是没出息的!这本证书你早该学!

一、程序员有没有必要学软考&#xff1f; 当然有&#xff0c;因为你不可能一辈子都是程序员。 你了解或者接触过30岁、35岁以上的程序员去向吗&#xff1f; 我毕业快十年了&#xff0c;当初正赶上互联网时代的浪潮&#xff0c;好几个学计算机的同学毕业后去了一线城市或者深…...

鸿蒙next版开发:相机开发-录像(ArkTS)

在HarmonyOS 5.0中&#xff0c;ArkTS提供了一套完整的API来管理相机功能&#xff0c;特别是录像功能。本文将详细介绍如何在ArkTS中实现录像功能&#xff0c;并提供代码示例进行详细解读。 录像功能开发步骤 1. 导入相关接口 首先&#xff0c;需要导入相机相关的接口&#x…...