对象的生离死别

对象的生离死别

实验介绍

在构建一个类时,一般情况下需要编写构造函数、拷贝构造函数以及析构函数,这将直接影响程序的运行。而初始化列表是在调用构造函数时初始化参数的方式。

一个对象从实例化到销毁的历程:

知识点
  • 内存分区
  • 构造函数
  • explicit 关键字
  • 初始化列表
  • 拷贝构造函数
  • 析构函数

内存分区

介绍

根据存储数据的类型,系统将不同类型的数据存储在不同的区域,作为 C++ 开发者,必须对内存的分区以及使用了然于心。

分区

一般情况下,根据内存用途将内存划分为五个区:

内存区用途解释
栈区存储函数的参数、局部变量等
堆区由程序员分配、释放内存
全局区存储全局变量和静态变量
常量区存储常量
代码区存储逻辑代码的二进制
栈与堆对比
功能
申请与释放编译器自动分配、回收程序员分配和释放(C 使用 malloc 申请内存、free 释放内存;C++ 使用 new 申请内存、delete 释放内存)
申请内存后系统的响应申请空间大于栈空间时程序将提示异常 (栈溢出)超过内存空间程序报异常
空间大小限制window 1 M / linux 8 M系统内存,比栈大很多
申请效率比较慢(只是相对栈,实际也很快)
示例代码 1
#include <iostream>
using namespace std;class Plan
{// 默认为私有属性int wingCount;
public:// 代码区Plan() { wingCount = 0; }~Plan() {}int getWingCount() { return wingCount; }
};int main()
{// 栈上Plan p1;Plan p2;Plan p3;p1.getWingCount();p2.getWingCount();p3.getWingCount();return 0;
}
代码解释
  • 编译时 getWingCount 只存储一份。
  • 实例化的对象 p1p2p3 存储在栈上。
  • 当对象调用 getWingCount 成员函数只需要找到相应地址即可。
  • 当变量没有被初始化时是一个随机值,建议所有变量都初始化。
  • 示例代码 1 中数据在类默认私有属性区域,但一般建议添加封装属性关键字。

构造函数

定义:构造函数又称构造方法、建构子、构造器,是类里用于创建对象的特殊子程序。可以初始化一个新建的对象,并时常接受参数用以设定实例变量。

规则与特点
  • 对象实例化时自动被调用。
  • 与类名同名。
  • 没有返回值。
  • 可以有多个重载形式。
  • 实例化对象时仅用到一个构造函数。
  • 当用户没有定义构造函数时,编译器自动生成。
示例代码 2
#include <iostream>
#include <string>
using namespace std;class Teacher
{
public:// 1. 无参构造函数Teacher() {}// 2. 有参构造函数Teacher(string name, int age) {this->name = name;this->age = age;}// 3. 有参构造函数--全部有默认参数-->默认构造函数/*Teacher(string name = "jake", int age = 15) {this->name = name;this->age = age;}*/
private:string name;int age;
};

注意:

  • 根据重载函数的规则,例如示例代码 2 中有参构造函数与缺省构造函数不能同时使用,因为参数的个数和类型都是相同的。
  • 示例代码 2 中无参构造函数与缺省构造函数也不能同时使用,因为编译器无法识别是使用无参构造函数还是使用缺省函数。
  • 如果实例化对象不需要传递参数的构造函数统称默认构造函数。
explicit 关键字

作用:指定构造函数或转换函数或推导指引为显示,即不能用于隐式转换赋值初始化。默认情况下类构造函数为 implicit(隐式)。

在讲解构造函数时需要提到 explicit 关键字,因为很多时候会使用到 explicit 关键字。

示例代码 3
#include <iostream>
#include <string>
using namespace std;class A
{
public:// 默认 implicit(隐式转换)A(int) { }      // 转换构造函数A(int, int) { } // 转换构造函数 (C++11)operator bool() const { return true; }
};class B
{
public:// 申明构造函数使用显示声明,不能隐式转换explicit B(int) { }explicit B(int, int) { }explicit operator bool() const { return true; }
};int main()
{A a1 = 1;      // OK赋值初始化选择 A::A(int)A a2(2);       // OK:直接初始化选择 A::A(int)A a3 {4, 5};   // OK:直接列表初始化选择 A::A(int, int)A a4 = {4, 5}; // OK赋值列表初始化选择 A::A(int, int)A a5 = (A)1;   // OK:显式转型进行 static_castif (a1) ;      // OK:A::operator bool()bool na1 = a1; // OK赋值初始化选择 A::operator bool()bool na2 = static_cast<bool>(a1); // OK:static_cast 进行直接初始化//  B b1 = 1;      // err赋值初始化不考虑 B::B(int)B b2(2);       // OK:直接初始化选择 B::B(int)B b3 {4, 5};   // OK:直接列表初始化选择 B::B(int, int)
//  B b4 = {4, 5}; // err赋值列表初始化不考虑 B::B(int,int)B b5 = (B)1;   // OK:显式转型进行 static_castif (b2) ;      // OK:B::operator bool()
//  bool nb1 = b2; // err赋值初始化不考虑 B::operator bool()bool nb2 = static_cast<bool>(b2); // OK:static_cast 进行直接初始化
}
  • 防赋值初始化时使用 explicit 关键字
  • 防赋值列表初始化时使用 explicit 关键字

拷贝构造函数

  • 语法格式:类名(const 类名 &变量)
  • 如果没有自定义构造函数,系统自动生成。
  • 采用直接初始化或赋值初始化实例化对象时系统自动调用拷贝构造函数。
示例代码 4
#include <iostream>
#include <string>
using namespace std;class Teacher
{
public:// 1. 无参构造函数Teacher() {}// 2. 有参构造函数Teacher(string name, int age) {this->name = name;this->age = age;}// 3. 拷贝构造函数Teacher(const Teacher &tea) {this->name = tea.name;this->age = tea.age;}
private:string name;int age;
};int main()
{// 执行默认构造函数Teacher tea1;// 执行拷贝构造函数Teacher tea2 = tea1;Teacher tea3 = Teacher(tea1);return 0;
}

注意:

  • 拷贝构造函数也是构造函数的一种,当执行了拷贝构造函数后就不会执行其他构造函数。
  • 如果不涉及深拷贝,可以不实现拷贝默认构造函数,使用系统自动生成的拷贝构造函数即可。

初始化列表

  • 先于构造函数执行。
  • 只能用于构造函数。
  • 可以同时初始化多个数据成员,多个数据成员之间使用逗号隔开。
示例代码 5
#include <iostream>
using namespace std;class Circle
{
public:Circle() : Pi(3.14) {}// 错误:Circle() { Pi = 3.14; }
private:const double Pi;
};

注意:

  • 语法格式:类名() : 数据成员 1(参数), 数据成员 2(参数) {}
  • 由于初始化列表先于构造函数执行,当类中有 const 常量时就必须要用到初始化列表来初始化。
  • 推荐使用初始化列表的方式来初始化数据成员。
  • 如果类中有数据成员时,推荐将数据成员都初始化。

析构函数

析构函数是在对象销毁时自动调用的函数,一般将释放内存的工作放在析构函数中完成。

  • 语法格式:~类名()
  • 析构函数不允许有任何参数、不允许重载、没有返回值。
  • 如果没有自定析构函数,系统自动生成。
  • 对象销毁时自动调用。
示例代码 6
#include <iostream>
using namespace std;class Student
{
public:Student() : buffer(new char[16]) {}~Student() {// 析构函数释放内存delete [] buffer;buffer = nullptr;}
private:char *buffer;
};

实验总结

类定义要素
  • 一个好的构造函数、拷贝构造函数和析构函数可以使程序使用更加稳健。
  • 在编写构造函数时需要考虑是否使用 explicit 关键字修饰。
  • 推荐在编写程序时使用初始化列表的方式初始化参数。
  • 析构函数时要注意释放堆中的内存,但也要注意避免重复释放内存造成程序崩溃。

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

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

相关文章

LabVIEW开发矿井排水监控系统

LabVIEW开发矿井排水监控系统 针对矿井水害对煤矿安全生产构成的威胁&#xff0c;设计了一种基于嵌入式PLC和LabVIEW的矿井排水监控系统。该系统结合了PLC的可靠控制与单片机的应用灵活性&#xff0c;有效克服了传统排水方法中的不足&#xff0c;如测量不准确、效率低下等问题…

ESP8266模块(CH340)零基础实战

USB数据线连接ESP8266模块到电脑 先按住FLASH键,再按一下RST键,然后松开 此时电脑可识别出CH340 COM接口 CH340芯片厂商网址: wch.cn 传输比特率9600 win11自带驱动 下载Arduino IDE

一文了解什么是Selenium自动化测试?

一、Selenium是什么&#xff1f; 用官网的一句话来讲&#xff1a;Selenium automates browsers. Thats it&#xff01;简单来讲&#xff0c;Selenium是一个用于Web应用程序自动化测试工具。Selenium测试直接运行在浏览器中&#xff0c;就像真正的用户在操作浏览器一样。支持的浏…

嵌入式系统复习--概述

文章目录 基本概念嵌入式系统的组成结构嵌入式操作系统嵌入式软件开发环境硬件基础简介下一篇 基本概念 嵌入式计算机&#xff1a;把嵌入到对象体系中、实现对象体系智能化控制的带有微控制器的计算机&#xff0c;称作嵌入式计算机 嵌入式系统&#xff1a;以应用为中心&#…

harmonyOS学习笔记之@Provide装饰器和@Consume装饰器

Provide和Consume&#xff0c;应用于与后代组件的双向数据同步&#xff0c;应用于状态数据在多个层级之间传递的场景。不同于State/Link装饰器修饰的 父子组件之间通过命名参数机制传递&#xff0c;Provide和Consume摆脱参数传递机制的束缚&#xff0c;实现跨层级传递。 其中Pr…

基于Java的招聘系统的设计与实现

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SSM 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 服务器&#xff1a;Tomcat8.5 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 目录…

OWASP Web 安全测试指南 WSTG

Eoin Keary的前言 软件不安全的问题可能是我们这个时代最重要的技术挑战。支持业务、社交网络等的 Web 应用程序的急剧兴起只会加剧建立一种强大的方法来编写和保护我们的 Internet、Web 应用程序和数据的要求。 在开放 Web 应用程序安全项目 &#xff08;OWASP&#xff09; 中…

HarmonyOS应用开发-手写板

这是一个基于HarmonyOS做的一个手写板应用&#xff0c;只需要简单的几十行代码&#xff0c;就可以实现如下手写功能以及清空画布功能。 一、先上效果图&#xff1a; 二、上代码 Entry Component struct Index {//手写路径State pathCommands: string ;build() {Column() {//…

RocketMQ-源码架构

源码环境搭建 1、主要功能模块 RocketMQ官方Git仓库地址&#xff1a;GitHub - apache/rocketmq: Apache RocketMQ is a cloud native messaging and streaming platform, making it simple to build event-driven applications. RocketMQ的官方网站下载&#xff1a;下载 | R…

C++STL算法库中谓词的使用

什么是c的谓词 谓词概念&#xff1a; 谓词函数是一个判断式&#xff0c;一个返回bool值的函数或者仿函数&#xff0c;有几个入参就是几元谓词。一般做一个函数的参数使用【引用自百度百科】。 常见的可以作为谓词的东西&#xff1a;函数、函数指针、函数对象、lambda表达式&am…

2023 年浙江省职业院校技能大赛信息安全管理与评估赛项规程

*2023 年浙江省职业院校技能大赛“高职组”* *“信息安全管理与评估”赛项规程* *一、赛项名称* 赛项名称&#xff1a;信息安全管理与评估 英文名称&#xff1a;Information Security Management and Evaluation 赛项组别&#xff1a;高职 赛项归属产业&#xff1a;电子信…

热电厂发电机组常见故障及预测性维护方法

热电厂的发电机组是关键的能源生产设备&#xff0c;在电力供应中扮演着关键角色。但经过长期运行和高负荷工作&#xff0c;一旦发生故障&#xff0c;可能导致停机、设备损坏甚至引发严重事故。因此&#xff0c;实施有效的预测性维护方法对于确保发电机组的稳定运行至关重要。本…

Linux(17):认识与分析登录档

什么是登录档 【详细而确实的分析以及备份系统的登录文件】是一个系统管理员应该要进行的任务之一。 登录档 就是记录系统活动信息的几个文件&#xff0c;例如&#xff1a;何时、何地(来源IP)、何人(什么服务名称)、做了什么动作(讯息登录啰)。 换句话说就是&#xff1a;记录系…

【MySQL】:表的操作

表的操作 一.创建表二.查看表结构三.修改表四.删除表 一.创建表 field 表示列名。 datatype 表示列的类型。 character set 字符集&#xff0c;如果没有指定字符集&#xff0c;则以所在数据库的字符集为准。 collate 校验规则&#xff0c;如果没有指定校验规则&#xff0c;则以…

MySQL系列(二)——日志篇

MySQL日志 主要包括错误日志、查询日志、慢查询日志、事务日志、二进制日志几大类。其中&#xff0c;比较重要的还要属二进制日志binlog&#xff08;归档日志&#xff09;和事务日志redo log&#xff08;重做日志&#xff09;和undo log&#xff08;回滚日志&#xff09;。 今…

fastdds共享内存实现原理

fastdds 共享内存分两个部分&#xff0c;一部分用于保存数据&#xff0c;一部分用于通信。 fastrtps_“UUID”:共享内存包括又两部分数据&#xff0c;BufferNode和segment_size, 用配置文件port_queue_capacity_指定BufferNode的数量&#xff0c;segment_size用于保存实际传输的…

智物发布MT6877平台无线AR智能眼镜参考设计,推动下一代无线AR发展

随着增强现实(AR)技术的不断发展&#xff0c;有线AR眼镜在连接和使用方面存在一些限制。为了解决这些问题&#xff0c;无线AR智能眼镜的推出势在必行。 新一代无线AR智能眼镜采用了天玑900&#xff08;MT6877&#xff09;平台作为参考设计&#xff0c;搭载了2.4GHz的八核处理器…

【rabbitMQ】Exchanges交换机

上一篇&#xff1a;springboot整合rabbitMQ模拟简单收发消息 https://blog.csdn.net/m0_67930426/article/details/134904766 本篇代码基于上一篇继续写 目录 Fanout 交换机 1. add queue 2. add Exchange 3.绑定队列 Direct 交换机 1. add queue 2. add Exchange 3.…

011 数据结构_哈希

前言 本文将会向你介绍哈希概念&#xff0c;哈希方法&#xff0c;如何解决哈希冲突&#xff0c;以及闭散列与开散列的模拟实现 1. 哈希概念 顺序结构以及平衡树中&#xff0c;元素关键码与其存储位置之间没有对应的关系&#xff0c;因此在查找一个元素时&#xff0c;必须要经…

CyclicBarrier、CountDownLatch、Semaphore 的用法

CyclicBarrier、CountDownLatch、Semaphore 的用法 CountDownLatch&#xff08;线程计数器 &#xff09; CountDownLatch 类位于 java.util.concurrent 包下&#xff0c;利用它可以实现类似计数器的功能。比如有一个任务 A&#xff0c;它要等待其他 4 个任务执行完毕之后才能执…