对象的生离死别

对象的生离死别

实验介绍

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

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

知识点
  • 内存分区
  • 构造函数
  • 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.hqwc.cn/news/266385.html

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

相关文章

C语言经典错误总结(一)

注&#xff1a;本文是结合《C陷阱和缺陷》所写&#xff01; 一.和 我们都知道在C语言中表示赋值操作符&#xff0c;表示比较&#xff0c;那么你知道为啥单等号为&#xff0c;双等号为比较吗&#xff1f; 这里扩展下&#xff1a;因为在C语言中赋值操作符相对于比较符号较常出…

deepface:实现人脸的识别和分析

deepface介绍 deepface能够实现的功能 人脸检测&#xff1a;deepface 可以在图像中检测出人脸的位置&#xff0c;为后续的人脸识别任务提供基础。 人脸对齐&#xff1a;为了提高识别准确性&#xff0c;deepface 会将检测到的人脸进行对齐操作&#xff0c;消除姿态、光照和表…

美团一面凉凉,怒刷3000前端面试题逆袭字节,含泪分享面经

前言 本人二本大学科班出身&#xff0c;首次面试美团一面凉了。先分享一下美团的凉经&#xff0c;希望大家做好避坑准备&#xff1a; 一面&#xff1a; 1.http和https的区别&#xff0c;非对称加密和对称加密的原理&#xff0c;还有http2和http1的区别&#xff08;多路复用、…

日志门面slf4j和各日志框架

简介 简单日志门面(Simple Logging Facade For Java) SLF4J主要是为了给Java日志访问提供一套标准、规范的API框架&#xff0c; 其主要意义在于提供接口&#xff0c;具体的实现可以交由其他日志框架&#xff0c;如log4j、logback、log4j2。 对于一般的Java项目而言&#xff…

31、卷积 - 参数 dilation 以及空洞卷积

在卷积算法中,还有一个不常见的参数叫做dilation(中文:膨胀)。 很多同学可能没听说过这个参数,下面看看这个参数有什么作用,用来控制什么的。 我们还是放这个经典的卷积运算图,图中是看不出 dilation 这个参数的存在的。 如果再换一张图呢,发现两图的区别了吗? 没错…

用微元思想求解三重积分——基于Matlab

仅作自己学习使用 1. 题目 求解下列三重积分&#xff0c;其中A&#xff0c;μ&#xff0c;r都是常数。 求解的准确性可以用下式进行评估&#xff1a; 听过考研数一张宇课程的朋友应该指导&#xff0c;求解三重积分就是就一个面包&#xff0c;我们将面包无限细分为一个小块&a…

【JAVA基础】----第一天

【JAVA基础】----第一天 命名规则注释方式对HelloWorld代码进行解释常量&#xff0c;进制转换和机器码展现计算过程常量类型1.字符串常量2.整数常量 提供了四种表现形式2.1 二进制2.2 八进制2.3 十进制2.4 十六进制2.5 进制之间的转化2.5.1 其他进制转化为十进制2.5.2 十进制转…

天津大数据培训机构品牌 数据分析师的发展方向

大数据专业还是有一定难度的&#xff0c;毕竟大数据开发技术所包含的编程技术知识是比较杂且多的如果是计算机专业的学生或者自身有一定基础的人学&#xff0c;相对来说会比较容易&#xff0c;但对于零基础小伙伴学习来说&#xff0c;想要学习大数据&#xff0c;难度还是很高的…

基于SpringBoot+Vue前后端分离的商城管理系统(Java毕业设计)

大家好&#xff0c;我是DeBug&#xff0c;很高兴你能来阅读&#xff01;作为一名热爱编程的程序员&#xff0c;我希望通过这些教学笔记与大家分享我的编程经验和知识。在这里&#xff0c;我将会结合实际项目经验&#xff0c;分享编程技巧、最佳实践以及解决问题的方法。无论你是…

RT-Thread 工程创建(1)

方式一&#xff0c; 利用已经有的bsp进行创建 距离BearPi IOT Std 板 1. 下载 RT-Thread 官方 Env工具a. 下载 [Env 工具下载](https://www.rt-thread.org/download.html#download-rt-thread-env-tool) &#xff0c; 并解压缩b. 将env注册到系统中, 这样就在右键菜单中出现&am…

【C++】POCO学习总结(十二):流(文本编解码、数据压缩、文件读写流等)

【C】郭老二博文之&#xff1a;C目录 1、说明 POCO提供了多种流类&#xff0c;与标准c IOStreams兼容。 大多数POCO流类被实现为过滤器&#xff0c;这意味着它们不写入或读取设备&#xff0c;而是从它们连接的另一个流。 2、文本编解码 2.1 说明 POCO提供了用于编码和解码…

Javaweb之前端工程打包部署的详细解析

6 打包部署 我们的前端工程开发好了&#xff0c;但是我们需要发布&#xff0c;那么如何发布呢&#xff1f;主要分为2步&#xff1a; 前端工程打包 通过nginx服务器发布前端工程 6.1 前端工程打包 接下来我们先来对前端工程进行打包 我们直接通过VS Code的NPM脚本中提供的…