【C++入门】构造函数析构函数

 

目录

 前言

 1. 类的默认成员函数

 2. 构造函数

  2.1 什么是构造函数

2.2 构造函数的特性

3. 析构函数

 3.1 什么是析构函数

 3.2 析构函数的特性


 前言

        前边我们已经了解了类和对像的基本概念,今天我们将继续深入了解类。类有6个默认成员函数,即使类中什么都不写(空类),编译器会自动生成6个默认成员函数。那么本期主要介绍的是构造函数和析构函数。

在这里插入图片描述

 1. 类的默认成员函数

         默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

即使是类中什么都不写,编译器也会自动生成以下6个默认成员函数:

 既然会默认生成那还有什么必要介绍呢?

       虽然编译器会默认生成,但也并不是适用于任何场景(一些自定义类型不适用),这时就需要我们自己实现,所以深入了解类内部默认成员函数非常有必要的。

 2. 构造函数

  2.1 什么是构造函数

我们先看下面这个例子:

class Date
{
public:void Init(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;d1.Init(2023, 11, 10);d1.Print();Date d2;d2.Init(2022, 11, 10);d2.Print();return 0;
}

 这种写法其实很不便捷,比如:

  • 每次创建对象需要手动调用
  • 可能出现忘记调用的情况

 为了使用便捷于是C++引入了新的玩法:

 构造函数(用于初始化)

2.2 构造函数的特性

 注意:

 构造函数的主要任务并不是开空间创建对象,而是初始化对象。

 构造函数有以下特性:

  • 函数名与类名相同
  • 无返回值
  • 创建对象时编译器自动调用对应的构造函数
  • 在对象生命周期中只调用一次
  • 构造函数可以重载 
class Data
{
public:Data(){_year = 6;_month = 6;_day = 6;}Data(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()
{Data d1;// 调用无参构造函数//通过无参构造函数创建对象时,对象后面不用跟括号,会被识别成函数调用Data d2(2023, 10, 20);// 调用带参的构造函数return 0;
}
  • 用户显式定义了构造函数,编译器将不再生成
class Date
{
public://显式定义了构造函数,编译器不再生成Date(int year, int month, int day){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
int main()
{	Date d1;//报错,没有合适的默认构造函数可用//创建对象时没有参数,应该调用无参构造,并且上述构造没有缺省值//编译器默认生成的构造初始化为随机值return 0;
}

我们再来看看自定义类型:

class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)、//类里的成员变量只是声明int _year;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;//创建Date对象d,没有写构造函数也会生成默认构造return 0;
}

默认生成的构造函数初始化分为两种:

  • 内置类型
  • 自定义类型

内置类型:编译器默认的构造函数会初始化为随机值(也可能是0,不同编译器之间有差别)

自定义类型:会调用它的默认构造

比如:

 _t会调用Time类里边的默认构造

 C++中将内置类型初始化为随机值是一个缺陷

 C++11 针对这个缺陷,打了补丁:

  • 内置类型成员变量在类中声明时可以给默认值

 默认构造函数有三种

  1. 无参的构造函数
  2. 全缺省的构造函数
  3. 我们没写编译器默认生成的构造函数

 注意:默认构造函数只能有一个

 比如:

class Date
{
public:Date(){_year = 1900;_month = 1;_day = 1;}Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};void Test()
{Date d1;//报错,无法通过编译//d1是无参对象,调用构造函数时编译器分不清要调用哪个
}

3. 析构函数

 3.1 什么是析构函数

 前边我们以经知道一个对象是怎么来的

 那一个对象又是怎么没的呢?

 析构函数:

完成对象中资源的清理工作

 它的功能与构造函数相反

对象在销毁时会自动调用析构函数,完成对象中资源的清理工作 

注意:

  • 析构函数不是完成对对象本身的销毁
  • 局部对象销毁工作是由编译器完成的

 3.2 析构函数的特性

   析构函数有以下特性:

  • 析构函数名是在类名前加上字符 ~。
  • 无参数无返回值类型。
  • 一个类只能有一个析构函数。
  • 若未显式定义,系统会自动生成默认的析构函数。
  • 析构函数不能重载
  • 对象生命周期结束时,自动调用析构函数(C++)

 析构函数的调用和构造函数很类似

对于类型处理也分为两种:

  • 内置类型
  • 自定义类型

 对于内置类型,自己写析构函数并没有意义

内置类型出了作用域系统就自动回收了

 在自定义类型才有意义

比如:栈

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){// CheckCapacity();array[_size] = data;_size++;}// 其他方法...~Stack(){if (_array){free(_array);_array = NULL;_capacity = 0;_size = 0;}}
private:DataType* _array;int _capacity;int _size;
};
void TestStack()
{Stack s;s.Push(1);s.Push(2);
}

 在栈使用结束后不需要手动调用

出了作用域自动销毁

它的行为和构造函数很相似:

  •  默认生成析构函数,行为跟构造类似
  •  内置类型成员不做处理
  •  自定义类型成员会去调用他的析构

 比如:

class MyQueue
{private://MyQueue生成默认构造要清理_pushst和_popst两个成员变量时//就会调用Stack类里的析构函数Stack _pushst;Stack _popst;int _size = 1;
};int main()
{//main函数结束清理对象//MyQueue类会自动生成默认析构函数行为如下://内置类型不做处理//自定义类型调用它的析构函数MyQueue mq;return 0;
}

 总结:

         如果类中没有申请资源时(动态内存管理),析构函数可以不写,直接使用编译器生成的默认析构函数,有资源申请时,一定要写,否则会造成资源泄漏,比如Stack类。

       好了以上便是本期的全部内容,构造函数和析构函数的理解非常重要,关键也就总结为一句话:创建哪个类的对象就调用哪个类的构造函数,销毁哪个类的对象就调用哪个类的析构函数。希望对你有所帮助,感谢阅读!

 

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

一款基于.Net开发、开源、支持多平台云存储文件管理器

目录 01 项目简介02 项目代码03 部分截图04 项目地址 今天给大家推荐一款基于基于.Net开发、开源的&#xff0c;支持多平台的云存储文件管理器。 01 项目简介 Camelotia是一款云存储文件管理器&#xff0c;基于.Net UI框架和ReactiveUI框架开发的&#xff0c;目前支持的平台有…

skynet学习笔记03— 服务

01、API newservice(name, ...)&#xff1a; 阻塞的形势启动一个名为 name 的新服务&#xff0c;待start函数执行完后会返回这个服务的地址。uniqueservice(name, ...)&#xff1a;针对于当前节点&#xff0c;启动一个唯一服务&#xff08;相当于单例&#xff09;&#xff0c;…

STM32F103C8T6第三天:pwm、sg90、超声波、距离感应按键开盖震动开盖蜂鸣器

1. 定时器介绍1&#xff08;317.21&#xff09; 软件定时&#xff08;之前的定时方法&#xff09;&#xff08;软件延时&#xff09;缺点&#xff1a;不精确、占用CPU资源 void Delay500ms() //11.0592MHz {unsigned char i, j, k;_nop_();i 4;j 129;k 119;do{do{while (-…

Flink SQL -- 概述

1、Flink SQL中的动态表和连续查询 1、动态表&#xff1a; 因为Flink是可以做实时的&#xff0c;数据是在不断的变化的&#xff0c;所以动态表指的是Flink中一张实时变换的表&#xff0c;表中会不断的有新的数据。但是这张表并不是真正的物理表。 2、连续查询&#xff1a; 连续…

网络安全深入学习第八课——代理与端口转发

文章目录 一、什么是代理二、正向代理三、反向代理四、正向和反向代理模拟复现 一、什么是代理 代理服务器英文全称是Proxy Server&#xff0c;其功能就是代理网络用户去取得网络信息。 形象的说&#xff1a;它是网络信息的中转站。在一般情况下&#xff0c;我们使用网络浏览…

自动驾驶学习笔记(八)——路线规划

#Apollo开发者# 学习课程的传送门如下&#xff0c;当您也准备学习自动驾驶时&#xff0c;可以和我一同前往&#xff1a; 《自动驾驶新人之旅》免费课程—> 传送门 《Apollo Beta宣讲和线下沙龙》免费报名—>传送门 文章目录 前言 路线规划 路由元素 路径搜索 最优…

P1529 [USACO2.4] 回家 Bessie Come Home 题解

文章目录 题目描述输入格式输出格式样例样例输入样例输出 提示完整代码 题目描述 现在是晚餐时间&#xff0c;而母牛们在外面分散的牧场中。 Farmer John 按响了电铃&#xff0c;所以她们开始向谷仓走去。 你的工作是要指出哪只母牛会最先到达谷仓&#xff08;在给出的测试数…

款网络拓扑自动扫描工具

Topology-Scanner是WeOps团队免费开放的一个网络拓扑自动扫描模块&#xff0c;可以自动发现网络设备的类型、网络设备之间的互联 使用方式 java -jar ./topology-scanner.jar --config_path./config/ 配置说明 1. 拓扑发现请求参数文件(request.json) ips [全网发现] 模式时…

欧拉角(横滚角、俯仰角、偏航角)、旋转矩阵、四元数的转换与解决万向节死锁

1、概述 物体的位姿&#xff08;位置和方向&#xff09;的描述方法一般使用两个坐标系来表示&#xff0c;一个是世界坐标系或地面坐标系&#xff0c;这里我都叫做地面坐标系吧&#xff0c;属于参考坐标系&#xff1b;另一个是自身的坐标系&#xff0c;以飞机为例来讲述一些常见…

selenium/webdriver运行原理与机制

最近在看一些底层的东西。driver翻译过来是驱动&#xff0c;司机的意思。如果将webdriver比做成司机&#xff0c;竟然非常恰当。 我们可以把WebDriver驱动浏览器类比成出租车司机开出租车。在开出租车时有三个角色&#xff1a; 乘客&#xff1a;他/她告诉出租车司机去哪里&a…

Redis的三种特殊数据类型

文章目录 一、Redis geospatial 地理位置二、Redis Hyperloglog 基数统计的算法三、Redis Bitmaps 位存储&#xff08;0、1&#xff09;总结 一、Redis geospatial 地理位置 1.geoadd&#xff1a;将指定的地理空间位置&#xff08;纬度、经度、名称&#xff09;添加到指定的ke…

【CocoaPods安装环境和流程以及各种情况】

CocoaPods 环境HomebrewRubyrbenvRubyGems 和 Bundler安装Ruby管理Ruby更新Ruby替换Ruby镜像方式1方式2 CocoaPods安装CocoaPodsCocoaPods使用安装的一些问题单元测试引用问题 参考的链接 环境 Homebrew $ brew --config *可以发现打印有下面一行&#xff1a; Homebrew Ruby: …

win10 下 ros + Qt 工程CMakeLists.txt

win10 下 ros Qt 工程CMakeLists.txt 系统&#xff1a;win10 ros: melodic Qt: 5.12.12 源码目录: D:\workspace\catkin_qt 示例代码 https://github.com/ncnynl/ros-qt.git 由于示例代码是Qt4 &#xff0c;目前我是用QT5,所以CMakeLists.txt 修改如下 CMakeLists.txt #####…

AI 绘画 | Stable Diffusion 进阶 Embeddings(词嵌入)、LoRa(低秩适应模型)、Hypernetwork(超网络)

前言 Stable Diffusion web ui&#xff0c;除了依靠文生图&#xff08;即靠提示词生成图片&#xff09;&#xff0c;图生图&#xff08;即靠图片提示词生成图片&#xff09;外&#xff0c;这两种方式还不能满足我们所有的绘图需求&#xff0c;于是就有了 Embeddings&#xff0…

odoo16 库存初始化 excel导入问题

最近在为一家公司实施odoo时&#xff0c;发现库存模块实施过程中按用户实际&#xff0c;产品初始化就是个问题。下面一一记录下 一个新公司&#xff0c;产品都有上百种&#xff0c;甚致几千种&#xff0c;如何把现有产品数据录入系统就是个不小的活。odoo16是有导入导出功能不…

数据结构与算法C语言版学习笔记(3)-线性表的链式结构:链表

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言&#xff1a;回顾顺序表的优缺点&#xff1a;为什么要引入链式结构的线性表&#xff1f; 一、什么是链表&#xff1f;二、链表的分类①为什么要设置头节点&…

卷积神经网络中参数量的计算原理及方法

手动计算参数量: 1. 卷积层参数计算方法: 参数量计算公式 卷积核高度 * 卷积核宽度 * 输入层通道数 * 输出层通道数 bias(输出层通道数) 注意:池化层没有参数(只是在已知数据区域里求个最大值)输入层通道数就是上层的卷积核数量 输出层通道数等于卷积核个数:输入层通道数经过…

007 Linux fork()函数

前言 本文将会以提问的形式展开向你介绍fork函数 文章重点 关于fork函数&#xff0c;本文重点在于解决以下疑问 疑问一&#xff1a; 为什么fork之前的代码只有父进程执行&#xff0c;然而fork之后的代码父子进程都要执行 疑问二&#xff1a; 1、既然fork之后父子进程会执行一…

手机玻璃盖板为什么需要透光率检测

手机盖板&#xff0c;也称为手机壳或保护套&#xff0c;是一种用于保护手机外观和延长使用寿命的装置。它们通常由塑料、硅胶、玻璃或金属等材料制成&#xff0c;并固定在手机外壳上,其中任何一个工序出现差错&#xff0c;都有可能导致手机盖板产生缺陷&#xff0c;例如漏油、透…

JavaScript如何实现钟表效果,时分秒针指向当前时间,并显示当前年月日,及2024春节倒计时,源码奉上

本篇有运用jQuery&#xff0c;记得引入jQuery库&#xff0c;否则不会执行的喔~ <!DOCTYPE html> <html> <head> <meta charset"utf-8"> <title></title> <meta name"chenc" content"Runoob"> <met…