4. C++构造函数和析构函数

news2024/11/24 18:36:23

一、对象的初始化和清理

  • C++中的面向对象来源于生活,每个对象也都会有初始设置以及对象销毁前的清理数据的设置,对象的初始化和清理也是两个非常重要的安全问题

    1. 一个对象或者变量没有初始状态,对其使用后果是未知的
    2. 使用完一个对象或变量,没有及时清理,也会造成一定的安全问题
    • 例如:生活中我们买的电子产品基本都会有出厂设置,在某一天我们不用时也会删除掉自己的信息数据以保证隐私
  • 每个对象与其他对象的区别:

    • 外在区别即对象名称
    • 内在区别则是对象自身属性值,即数据成员的值
  • C++利用构造函数析构函数解决上述问题,这两个函数会被编译器自动调用,完成对象初始化和清理工作

    • 对象的初始化和清理工作是编译器强制要我们做的事情,如果没有提供构造和析构,编译器会提供该函数的空实现
    • 构造函数:创建对象时,为对象的成员属性赋值
    • 析构函数:对象销毁前,系统自动调用,执行一些清理工作

二、构造函数(constructor)

2.1 构造函数的定义形式

类名(参数说明){
    初始化代码
}

2.2 构造函数的特点

  • 构造函数的名字必须与类的名字相同
  • 定义构造函数时不能指定返回类型
  • 构造函数的代码与其他函数一样,但一般不直接调用(不显示调用)
  • 创建类的一个新对象时,会隐式地自动调用构造函数。即当程序中声明一个新对象时,程序会自动调用该对象所属类中定义的构造函数来初始化这个对象的状态
  • 若在定义类时没有定义构造函数,C++会自动为该类创建一个缺省(default)的构造函数。该缺省构造函数没有任何形式参数,且函数体为空。

例子:

# include <iostream>
using namespace std;

// 对象的初始化和清理
// 构造函数	进行初始化操作
// 析构函数,进行清理操作
class Person {
public:
	//定义构造函数,编译器自动调用
	Person() {
		cout << "Person 构造函数调用" << endl;
	}

	//定义析构函数,自动调用
	~Person() {
		cout << "Person 析构函数调用" << endl;
	}
};

int main() {
	Person p;
}
image-20230509111435308

2.3 有参构造函数和无参构造函数

  • 构造函数定义中,在冒号之后、函数体之前是初始化列表
  • 有参构造函数:定义构造函数时带有形参,那么建立对象时必须要给出初始值,用于作为调用构造函数时的实参
  • 调用时可以不需要参数的构造函数都是无参构造函数,也称为默认构造函数
    • 不定义构造函数时,编译器自动产生默认构造函数
    • 在类中可以自定义无参数的构造函数,也是默认构造函数
    • 全部参数都有默认形参值的构造函数也是默认构造函数
  • 一个系统只能有一个默认构造函数

示例:

#include <iostream>
using namespace std;    

class Clock{
public:
    // 定义了两个Clock构造函数,即为构造函数的重载
    Clock(int newH, int newM, int newS);	// 定义有参构造函数
    Clock();							  // 定义无参构造函数
    /*
    // 每个参数都有默认值,属于默认构造参数
    Clock(int newH = 0, int newM = 0, int newS = 0);
    调用方式:
    Clock c1(8, 30, 30);
    Clock c2(8);
    Clock c3;	// 这种方式也可以使用Clock()定义无参构造函数,因此类中不可同时存在这两种构造函数的定义方式
    */
    
    void setTime(int newH, int newM, int newS);
    void showTime();
private:
    int hour, minute, second;
};

// 有参构造函数的实现
// 冒号之后,函数体之前部分称为 初始化成员列表
// 将初始化传入的三个数据newH、newM、newS的值分别给hour、minute、second
Clock::Clock(int newH, int newM, int newS):hour(newH), minute(newM), second(newS){ 
}
/* 等价于
Clock::Clock(int newH, int newM, int newS){
    hour = newH;
    minute = newM;
    second = newS;
}
*/

// 无参构造函数的实现
Clock::Clock(): hour(1), minute(1), second(1){
}
/* 等价于
Clock::Clock(){
    hour = 1;
    minute = 1;
    second = 1;
}
*/

// 成员函数
void Clock::setTime(int newH, int newM, int newS){
    hour = newH;
    minute = newM;
    second = newS;
}
void Clock::showTime(){
    cout << hour << ":" << minute << ":" << second << endl;
}

int main(){
    Clock myClock1;		        // 定义对象,此时自动调用无参构造函数
    myClock1.showTime();
    
    Clock myClock2(8, 3, 30);	// 定义对象,此时自动调用有参构造函数
    myClock2.showTime();
    
    return 0;
}

2.4 复制构造函数

  • 具有一般构造函数的所有特性,其形参是本类的对象的引用

  • 作用:使用一个已经存在的对象,该对象由复制构造函数的形参指定,去初始化 同类 的一个新对象

  • 语法:

    class 类名 {
    public:
        类名(形参表);		// 构造函数
        类名(类名 &对象名);   // 复制构造函数
        ...
    };
    
    // 复制构造函数的定义
    类名::类名(类名 &对象名){ 
    }	
    
  • 类内声明,类外实现

2.4.1 复制构造函数的三种使用情形

  1. 定义一个对象时,以本类另一个对象作为初始值

    Point a(10, 20);
    Point b = a;
    
  2. 传参

    void fun1(Point p){
        cout << p.getX() << endl;
    }
    
    // 调用语句
    fun1(b);
    
  3. 函数值返回

    Point fun2(){
        return Point(1, 2);
    }
    
    // 调用语句
    b = fun2();
    

三、析构函数(destructor)

3.1 析构函数的定义形式

~类名() {
    
}

3.2 析构函数的特点

  • 析构函数的名字必须是在类名前加上一个波纹号“~”,以区别于构造函数;
  • 定义析构函数时也不能指定返回类型
  • 在对象消亡时,隐式地自动调用析构函数。即当程序中一个对象作用结束时,程序会自动调用该对象所属类中定义的析构函数来清除这个对象所占的存储空间
  • 若在定义类时没有定义析构函数,C++会自动为该类创建一个缺省的析构函数。这个缺省析构函数没有任何形式参数,且函数体为空。

3.3 析构函数的实现

#include <iostream>
using namespace std;

class DemoClass{
public:
    DemoClass(int i);	// 函数名与类名一样,因此是构造函数
    ~DemoClass();		// 函数名与类名一样,且开头有~,因此是析构函数   	
};

// 构造函数的实现
DemoClass::DemoClass(int i){
    cout << "Initial value is" << i << endl;
}

// 析构函数的实现
DemoClass::~DemoClass(){
    cout << "destructor" << endl;
}

void main(){
    DemoClass obj(30);	// 创建对象,同时自动调用构造函数DemoClass()
    cout << "This is the end main()" << endl;
    return;	// 函数执行结束,创建的对象生命结束,自动调用析构函数~DemoClass()
}
image-20220605223805453

四、类对象作为类成员

  • C++类中的成员可以是另一个类的对象,称该成员为对象成员
  • 例如:B类中有对象A作为成员,A为对象成员
class A{}
class B{
    A a;
}
  • 创建B对象时,A与B的构造和析构的顺序:
    • 构造顺序:先调用对象成员的构造,再调用本类的构造
    • 析构顺序:与构造顺序相反
# include <iostream>
# include <string>
using namespace std;

// 手机类
class Phone {
public:
	Phone(string name) {
		m_PhoneName = name;
		cout << "Phone构造" << endl;
	}

	~Phone() {
		cout << "Phone析构" << endl;
	}

	string m_PhoneName;
};

// 人类
class Person {
public:

	Person(string name, string pName) : m_Name(name), m_Phone(pName) {
		cout << "Person构造" << endl;
	}

	~Person() {
		cout << "Person析构" << endl;
	}

	void playGame() {
		cout << m_Name << " 使用" << m_Phone.m_PhoneName << " 牌手机!" << endl;
	}

	string m_Name;	// 姓名
	Phone m_Phone;	// 手机,手机类对象
};

void test01() {
	// 当类中成员是其他类对象时,我们称该成员为 对象成员
	// 构造的顺序是:先调用对象成员的构造,再调用本类构造
	// 析构的顺序与构造相反
	Person p("张三", "苹果X");
	p.playGame();
}

int main() {
	test01();
}
image-20221017005820482

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

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

相关文章

CentOS7安装Maven详细教程

&#x1f60a; 作者&#xff1a; Eric &#x1f496; 主页&#xff1a; https://blog.csdn.net/weixin_47316183?typeblog &#x1f389; 主题&#xff1a;CentOS7安装Maven详细教程 ⏱️ 创作时间&#xff1a; 2023年08月06日 第一步&#xff1a;上传或下载安装包&#x…

【Element】el-cascader 级联选择器

ElementUI label 为空的不展示 将children设为undefined dg(list) {list.forEach(item > {item.label item.nameitem.value item.iditem.children item.childrenList.length ! 0 ? item.childrenList : undefinedif (item.children) {this.dg(item.children)}}) },第…

拦截器对接口细粒度权限校验

文章目录 一、逻辑分析二、校验规则1.规则类型2.规则划分3.规则配置信息4.规则案例说明5.规则加载 三、拦截器定义1.自定义拦截器2.注册拦截器 四、获取请求参数1.获取get提交方式参数2.获取post提交方式参数&#xff08;1&#xff09;定义RequestWrapper类&#xff08;2&#…

pinctrl_desc结构体注册

pinctrl_desc结构体注册 文章目录 pinctrl_desc结构体注册pinctrl_registerpinctrl_register_pins注册所有的引脚 pinctrl_register 构建好struct pinctrl_desc结构以后&#xff0c;会调用pinctrl_register函数注册一个pinctrl控制器&#xff0c;得到一个pinctrl_dev struct …

【大数据】Flink 详解(二):核心篇 Ⅰ

Flink 详解&#xff08;二&#xff09;&#xff1a;核心篇 Ⅰ 14、Flink 的四大基石是什么&#xff1f; ​ Flink 的四大基石分别是&#xff1a; Checkpoint&#xff08;检查点&#xff09;State&#xff08;状态&#xff09;Time&#xff08;时间&#xff09;Window&#xff…

【机器学习2】什么是Jupyter notebook 新手使用Jupter notebook

什么是Jupyter notebook? Jupyter Notebook&#xff08;此前被称为 IPython notebook&#xff09;是一个交互式笔记本&#xff0c;支持运行 40 多种编程语言。 Jupyter Notebook 的本质是一个 Web 应用程序&#xff0c;便于创建和共享程序文档&#xff0c;支持实时代码&#x…

Redis 7.X Linux 环境安装

Redis 简介 作为一名开发人员&#xff0c;想必大家对Redis一定是耳熟能详&#xff0c;因此在此只做简单介绍。 Remote Dictionary Server(远程字典服务)是完全开源的&#xff0c;使用ANSIC语言编写遵守BSD协议&#xff0c;是一个高性能的Key-Value内存数据库&#xff0c;它提…

命令模式(C++)

定义 将一个请求(行为)封装为一个对象&#xff0c;从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志&#xff0c;以及支持可撤销的操作。 应用场景 在软件构建过程中&#xff0c;“行为请求者”与“行为实现者”通常呈现一种“紧耦合”。但在某些场合——比…

iPhone苹果手机地震预警功能怎么开启?

iPhone苹果手机地震预警功能怎么开启&#xff1f; 1、打开iPhone苹果手机设置&#xff1b; 2、在iPhone苹果手机设置内找到辅助功能&#xff1b; 3、在辅助功能内找到触控&#xff1b; 4、在iPhone苹果手机辅助功能触控内找到振动&#xff0c;如果是关闭状态请启&#xff1b; …

jdk1.7与jdk1.8中String.split()方法问题

split切割字符串的坑&#xff0c;会有索引越界的风险。 在jdk1.8中 public static void main(String[] args) { String card "abcdefgh"; System.out.println(card.split("").length); } 结果&#xff1a;8 在jdk1.7中&#xff0c;同样的代码 …

kubectl 详解(陈述式资源管理与声明式资源管理)

目录 一、kubectl简介 二、kubectl基础命令 三、基本信息查看 1.查看标签信息 ​2. 查看 master 节点状态 3. 查看命名空间 4.创建、删除命名空间app 5.在命名空间kube-public 创建副本控制器&#xff08;deployment&#xff09;来启动Pod&#xff08;nginx-www&#xf…

网关 GateWay 的使用详解、路由、过滤器、跨域配置

一、网关的基本概念 SpringCloudGateway网关是所有微服务的统一入口。 1.1 它的主要作用是&#xff1a; 反向代理&#xff08;请求的转发&#xff09; 路由和负载均衡 身份认证和权限控制 对请求限流 1.2 相比于Zuul的优势&#xff1a; SpringCloudGateway基于Spring5中…

libcurl网络库的函数接口使用

文章目录 1、libcurl简介2、libcurl的使用3、函数简介4、 curl_easy_setopt函数部分选项介绍5、curl_easy_perform 函数说明&#xff08;error 状态码&#xff09;6、简单实例,包含库文件&#xff0c;头文件即可 1、libcurl简介 libcurl是一个跨平台的网络协议库&#xff0c;支…

【福建事业单位-推理判断】02图形推理(数量-空间重构)

【福建事业单位-推理判断】02图形推理&#xff08;数量-空间重构&#xff09; 一、数量规律1.1点&#xff08;交点、切点&#xff09;点的细化考法总结 1.2线条&#xff08;线条的数量&#xff09;线的细化考点一笔画&#xff08;重点&#xff09;一笔画的判定 总结 1.3 面面的…

PWNlab靶机渗透

安装靶机 下载地址&#xff1a;https://www/vulnhub.com/entry/pwnlab-init,158/ 信息收集&#xff1a; 收集靶机ip地址&#xff0c;由于搭建在本地使用kali自带命令 arp-scan -l nmap 扫描端口&#xff0c;服务 nmap -sV -p 1-65535 -A 靶机ip地址 漏洞探测 访问80端口地…

LeetCode--HOT100题(21)

目录 题目描述&#xff1a;240. 搜索二维矩阵 II&#xff08;中等&#xff09;题目接口解题思路代码 PS: 题目描述&#xff1a;240. 搜索二维矩阵 II&#xff08;中等&#xff09; 编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性&am…

2023 RISC-V中国峰会 安全相关议题汇总

安全相关议题 1、The practical use cases of the RISC-V IOPMP 2、构建安全可信、稳定可靠的RISC-V安全体系 3、Enhancing RISC-V Debug Security with hardware-based isolation 4、Closing a side door: Designing high-performance RISC-V core resilient to branch pr…

javascript:js介绍初体验和变量以及数据类型的使用。

目录 一.介绍 1概念 2作用 3组成 二.js初体验 1.js的书写位置 a.行间引入 b.内部引入 c.外部引入​编辑 2.js的注释 3.js的结束符 4.输入输出语句 输出语法 输入语法 三.变量及数据类型 ​ 1.字面量 2.变量 ​编辑 变量的使用 ​编辑 let和var的区别…

力扣17(电话号码中的字符组合)

题目表述 给定一个仅包含数字 2-9 的字符串&#xff0c;返回所有它能表示的字母组合。答案可以按 任意顺序 返回。 给出数字到字母的映射如下&#xff08;与电话按键相同&#xff09;。注意 1 不对应任何字母。 示例1 输入&#xff1a;digits "23" 输出&#xff1…

用html+javascript打造公文一键排版系统16:更新单个附件说明排版,实现多个附件说明排版

利用公休的时间继续完善。 一、更新单个附件说明排版 之前实现单个附件说明排版时&#xff0c;我们只考虑了“附件&#xff1a;”中冒号为半角的情况&#xff0c;而没有考虑存在多任余空格的情况&#xff0c;我们今天先针对存在多任余空格的情况进行完善&#xff0c;增加了温…