析构函数、拷贝构造

news2024/11/14 13:47:27

1、析构函数

析构函数的定义方式

函数名和类名相同,在类名前加~,没有返回值类型,没有函数形参(不能重载)

当对象生命周期结束的时候,系统会自动调用析构函数

先调用析构函数,再释放对象的空间

析构函数实现

#include <iostream>

using namespace std;
class Person
{
private:
    int mAge;
public:
    //无参构造
    Person(){
        cout<<"无参构造:"<<endl;
    }
    //无参构造
    Person(int age){
        mAge = age;
        cout<<"有参构造:"<<mAge<<endl;
    }
    //没有 void 和返回值
    ~Person(){
         cout<<"析构函数:"<<mAge<<endl;
    }
};

void test(){
    Person(20);
    {
        Person(30);
    }
    Person(40);
}

int main(int argc, char *argv[])
{
    Person p1(10);
    test();
    return 0;
}

构造函数和析构函数的执行次序(面试题)

说白了函数从上到下执行,先执行到的先进栈,先执行有参或者无参构造,后退栈的后执行,执行析构函数

一般情况下,空的析构函数就足够,但是如果一个类有指针成员,这个类必须写析构函数,释放指针成员所指向空间

因为一个对象结束,系统默认回收的是这个对象本身的空间,但是它不会回收这个对象中指针成员指向的空间,所以如果一个类有指针成员,这个类必须写析构函数,释放指针成员所指向空间


#include <iostream>
#include <string.h>
#include <stdlib.h>

using namespace std;
class Person
{
private:
    char *mName;
public:
    Person(){
        mName = NULL;
    }
    Person(char *name){
       mName = new char [strlen(name)+1];   //申请堆区空间
       strcpy(mName,name);
       cout<<"有参构造:"<<mName<<endl;
    }
    //没有 void 和返回值
    ~Person(){
        if(mName != NULL){
            delete [] mName;
            cout<<"释放 Person 类的指针成员所指行向的 堆区空间"<<endl;
        }
    }
};

int main(int argc, char *argv[])
{
    Person ml("ml");
    return 0;
}

最后调用析构函数释放掉 Person 类的指针成员所指行向的 堆区空间

2、拷贝构造

实现拷贝构造

 //Person类中的深拷贝
    Person(const Person &ob){
        mName = new char [strlen(ob.mName)+1];   //申请堆区空间
        strcpy(mName,ob.mName);
        cout<<"有参构造:"<<ob.mName<<endl;
    }

Person ml("ml");
Person m = ml;  //深拷贝

拷贝构造本质是构造函数

在上面的代码中,旧对象给新对象初始化就会调用拷贝构造函数,ob就是旧对象的引用

系统默认的拷贝是浅拷贝,能完成基本的赋值操作,一旦实现了拷贝构造函数必须实现赋值操作,因为系统默认的函数以及无效了

const Person &ob 代表的是当前类的常引用,因为我们不希望改变参数值,所以是 const 类型的

实现深拷贝的必要性

当执行下面的代码的时候,新对象 m 中的成员指针 和 旧对象 ml 中的成员指针都会指向 堆区空间字符串为 “ml”的地址,那么 ml 在结束的时候会调用析构函数释放掉该堆区空间,而 m 在结束的时候也会调用析构函数释放掉该堆区空间

Person ml("ml");
Person m = ml;  //深拷贝

所以上面的情况就是,新旧对象中的指针成员指向同一块堆区空间,于是新旧对象对同一块堆区空间释放掉了两次,造成了堆区空间的多次释放,这就是浅拷贝存在的问题

这个时候就需要使用到深拷贝,让新对象中的指针成员指向新的堆区空间,那么新旧对象释放的时候就不会多次释放同一块堆区空间,这就解决了浅拷贝存在的问题

//Person类中的深拷贝
    Person(const Person &ob){
        mName = new char [strlen(ob.mName)+1];   //新对象申请属于自己的堆区空间
        strcpy(mName,ob.mName);
        cout<<"有参构造:"<<ob.mName<<endl;
    }
#include <iostream>
#include <string.h>
#include <stdlib.h>

using namespace std;
class Person
{
private:
    char *mName;
public:
    //无参构造
    Person(){
        mName = NULL;
    }
    //有参构造
    Person(char *name){
       mName = new char [strlen(name)+1];   //申请堆区空间
       strcpy(mName,name);
       cout<<"有参构造:"<<mName<<endl;
    }
    //深拷贝
    Person(const Person &ob){
        mName = new char [strlen(ob.mName)+1];   //新对象申请属于自己的堆区空间
        strcpy(mName,ob.mName);
        cout<<"有参构造:"<<ob.mName<<endl;
    }

    //析构函数
    ~Person(){
        if(mName != NULL){
            delete [] mName;
            mName = NULL;
            cout<<"释放 Person 类的指针成员所指行向的 堆区空间"<<endl;
        }
    }
};

int main(int argc, char *argv[])
{
    Person ml("ml");
    Person m = ml;  //深拷贝
    return 0;
}

3、注意事项

析构函数没有 void 和 返回值

如果用户定义了有参构造或者拷贝构造,都会屏蔽系统默认无参构造,所以这种情况最好是有自定义的无参构造,不会编译会出错

如果用户定义了有参构造或者无参构造,不会屏蔽拷贝构造

默认的拷贝都是浅拷贝(能完成基本的操作)

如果类中没有指针成员,不用实现构造拷贝和析构函数

如果类中有指针成员而且指向堆区空间,必须实现析构函数释放指针成员指向的堆区空间,必须实现拷贝构造完成深拷贝动作

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

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

相关文章

C#中多态、抽象类、虚方法

多态、重装、重写 •多态&#xff1a;同一操作作用于不同的对象&#xff0c;可以有不同的解释&#xff0c;产生不同的执行结果&#xff0c;这就是多态性。抽象类、虚函数、接口三种方法实现的可以是多态性。•重载&#xff08;overload&#xff09;&#xff1a;对象中同名函数&…

【Galois工具开发之路】给你的JVM安装一个插件~

什么是DCEVM Dcevm&#xff08;DynamicCode Evolution Virtual Machine&#xff09;是Java Hostspot的一个扩展插件&#xff0c;属于开源性工具&#xff0c;非JDK官方提供&#xff0c;它允许你在运行环境下修改加载的类文件。当前虚拟机只允许修改方法体&#xff08;Method&am…

【Python学习笔记】43.Python3 JSON 数据解析及日期和时间

前言 本章介绍python的JSON及日期和时间。 Python3 JSON 数据解析 JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式。 Python3 中可以使用 json 模块来对 JSON 数据进行编解码&#xff0c;它包含了两个函数&#xff1a; json.dumps(): 对数据进行编码。json…

苏宁基于 AI 和图技术的智能监控体系的建设

汤泳&#xff0c;苏宁科技集团智能监控与运维产研中心总监&#xff0c;中国商业联合会智库顾问&#xff0c;致力于海量数据分析、基于深度学习的时间序列分析与预测、自然语言处理和图神经网络的研究。在应用实践中&#xff0c;通过基于 AI 的方式不断完善智能监控体系的建设&a…

C# 业务单据号生成器(定义编号规则、自动获取编号)

系列文章 C#底层库–数据库访问帮助类&#xff08;MySQL版&#xff09; 本文链接&#xff1a;https://blog.csdn.net/youcheng_ge/article/details/126886379 C#底层库–JSON帮助类_详细&#xff08;序列化、反序列化、list、datatable&#xff09; 本文链接&#xff1a;htt…

用友Java架构师面试

自我介绍。项目中的一些优化。Q&#xff1a;kafka消息的时序性怎么保证&#xff1f;A1&#xff1a; 核心意思就是要实现局部有序&#xff0c;需要有序的消息应设置相同的key&#xff0c;这样通过哈希取模后会分到同一个partition。又因为一个partition只能被一个consumer组中的…

智慧校园信息化管理平台技术方案

1.2总体架构设计 智慧校园平台是以学校现有网络为基础&#xff0c;以服务于全校师生的教学、科研、生活为目的&#xff0c;建立在学校数据中心平台之上&#xff0c;涵盖了学校的学校管理、学生管理、教学管理、班级管理、家校共育、教务管理等全方位的管理信息平台与信息服务平…

阿里P8经验分享 —— 送给想要学习自动化测试的同学6条建议

基于我的经验&#xff0c;送给想要学习自动化测试的同学6条建议 第一条建议&#xff1a;先学习编程语言&#xff0c;然后再接触自动化工具。 语言选择上Java或者Python都是可以的&#xff0c;可以先从Python入手&#xff0c;之后再开始Java。在学习语言的过程中&#xff0c;一…

playwright python环境运行报错 ImportError: DLL load failed

网上建议网上好多文章介绍playwright的环境搭建&#xff0c;用以下两条语句即可完成pip install playwrightplaywright install安装完毕后&#xff0c;尝试执行一段经典的python demofrom playwright.sync_api import sync_playwright with sync_playwright() as p: browser p…

seo优化案例截图

点击进入》》三支一扶课程聚合页面 百度统计数据 流量稳步增长&#xff0c; 2022年9月比2021年9月 同期增长 约30%。

SpringCloud - Nacos

目录 服务注册到Nacos 服务分级存储模型 NacosRule负载均衡 服务实例的权重设置 环境隔离 Nacos与Eureka的对比 添加Nacos配置 微服务配置拉取 配置热更新 多环境配置共享 服务注册到Nacos 1.在父工程引入SpringCloudAlibaba的依赖 2.注释掉order-service和user-ser…

@KafkaListener 详解及消息消费启停控制

参考&#xff1a;Kafka参数一、KafkaListener注解KafkaListener(id "11111", groupId "demo-group",topics Constants.TOPIC)public void listen(String msgData) {LOGGER.info("收到消息" msgData); } KafkaListener(id "22222"…

React系列之Redux

1 Redux概述 Redux 是 JavaScript 状态容器&#xff0c;提供可预测化的状态管理。Redux中文文档 Redux 和react没有必然关系&#xff0c;redux可以应用于各种框架&#xff0c;包括jquery&#xff0c;甚至js都可以使用redux&#xff0c;只不过redux和react更加搭配。redux也推…

javaee之git

一张图说明git 分支之间的操作 这个 框里面的linux命令都可以用 操作开始&#xff1a; 在master分支里面创建了一个hello.txt&#xff0c;并且放入了一些数据进去 这个去查一下日志 问题&#xff1a;当你放入了暂存区&#xff0c;你去查看日志会报错 一个分支这个指针head永…

Django框架之Django使用自带模板

Django使用自带模板 1 配置 在工程中创建模板目录templates。 在settings.py配置文件中修改TEMPLATES配置项的DIRS值&#xff1a; TEMPLATES [{BACKEND: django.template.backends.django.DjangoTemplates,DIRS: [os.path.join(BASE_DIR, templates)], # 此处修改APP_DIR…

vue-router 的基本用法

vue-router 的基本用法 1.什么是 vue-router vue-router 是 vue.js 官方给出的路由解决方案。它只能结合 vue 项目进行使用&#xff0c;能够轻松的管理 SPA 项目中组件的切换。 vue-router 的官方文档地址&#xff1a;https://router.vuejs.org/zh/ 2.vue-router 安装和配置的…

GIT分支管理策略

git基本操作git操作的前提条件:本地windows安装git学习idea中的插件使用idea的git基本操作:远程仓库remote更新fetch:git fetch拉取pull: git pull上传push: git push合并merge: git merge 合并分支本地提交commit:git commit分支branch: git branch 查看分支或者 切换分支上述…

SpringBoot整合Junit

创建项目 idea创建空项目Empty Project。项目中创建模块&#xff0c;选择SpringBoot Initialize快速构建SpringBoot项目。 依赖这里什么也不用选择。 pom文件中默认有两个依赖: spring-boot-starter springboot如果不导入任何依赖&#xff0c;默认的一个基础依赖。spring-…

5.3 线程安全问题解决方案

文章目录1.概述2.同步和异步3.synchronized同步关键字3.1 写法3.2 前提3.3 特点4.练习-改造售票案例-继承Thread4.1 代码实现4.2 注意事项5.练习-改造售票案例-实现Runnable接口5.1 代码实现5.2 注意事项6.练习-改造售票案例-使用线程池6.1 代码实现6.2 代码分析7.线程锁7.1 悲…

七、确保web安全的HTTPS

HTTPS 1、HTTP 的缺点 HTTP的主要缺点&#xff1a; 通信使用明文&#xff08;不加密&#xff09;&#xff0c;内容可能会被窃听 HTTP 本身不具备加密的功能&#xff0c;因此无法做到对通信整体&#xff08;使用 HTTP 协议通信的请求和响应的内容&#xff09;进行加密。所以按…