C++(构造和析构)

目录

1. 构造函数

1.1 概念

1.2 构造函数的分类

1.2.1 默认构造函数

1.2.2 带参数的构造函数

1.2.3 拷贝构造函数

1.2.4 移动构造函数

2. 析构函数

2.1 概念

3. 每期一问

3.1 上期答案


1. 构造函数

1.1 概念

在C++中,构造函数(Constructor)是一种特殊的成员函数,用于初始化对象的新实例。构造函数的名称与类的名称相同,并且没有返回类型(包括void)。当创建一个类的新对象时,构造函数被自动调用,以确保对象在被使用之前具有适当的初始状态。

构造函数的主要目的是:

  1. 初始化对象的数据成员: 构造函数负责设置对象的初始状态,将数据成员初始化为适当的值。

  2. 分配资源(如果需要): 如果对象需要动态分配内存或者需要执行其他资源分配操作,构造函数可以在对象创建时进行。

  3. 执行其他初始化操作: 构造函数可以执行其他与对象相关的初始化操作,如打开文件、建立网络连接等。

构造函数可以有多个重载版本,这意味着可以根据不同的参数列表来调用不同的构造函数。当没有定义构造函数时,编译器会提供一个默认构造函数,它会执行默认的初始化操作(如默认初始化或者零初始化)。需要注意的是:编译器提供的默认构造函数只会初始化非内置类型(如int,char等)。

示例:

class Example {
public:
	//构造函数的名称必须和类名相同,且没有返回值
	//构造函数我们使用全缺省参数
	//当我们不提供构造函数的时候,编译器会提供一个默认构造函数,自动调用非内置类型的
    //默认构造函数
	//注:编译器不对内置类型进行初始化操作
	Example(int year = 1, int month = 1, int day = 1)
	{
	    cout << "已调用Example" << endl;
		_year = year;
		_month = month;
		_day = day;
	}

	void prin()
	{
		 cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{

	Example E;
	E.prin();

}

执行结果如下:

1.2 构造函数的分类

构造函数是一种特殊的函数,它在创建对象时被自动调用。构造函数可以用来初始化对象的成员变量,确保对象在创建时拥有合适的状态。下面是构造函数的分类以及调用方式:

1.默认构造函数: 默认构造函数是没有参数的构造函数,如果没有定义任何构造函数,则编译器会自动生成一个默认构造函数。默认构造函数的调用方式是直接使用类名创建对象即可

2.带参数的构造函数: 带参数的构造函数是可以接受参数的构造函数,可以通过它来初始化对象的成员变量。带参数的构造函数可以有多个不同的版本,每个版本可以接受不同类型和数量的参数。带参数的构造函数的调用方式是在创建对象时传入相应的参数。

3.拷贝构造函数: 拷贝构造函数是用于复制一个对象的构造函数,它接受一个同类型的对象作为参数,并且会创建一个新的对象,该对象的成员变量与参数对象相同。拷贝构造函数的调用方式是在创建新对象时,将现有对象作为参数传递给它。

4.移动构造函数: 移动构造函数是C++11新增的一种构造函数,它接受一个右值引用作为参数,并且将其内部状态移动到新创建的对象中。移动构造函数通常比拷贝构造函数更高效。移动构造函数的调用方式是在创建新对象时,将一个右值对象作为参数传递给它。

1.2.1 默认构造函数

综上所述,我们了解默认构造函数,那我们接下来就见见面吧。

class Example {
public:	
//首先在这里定义了一个默认构造函数
	Example()
	{
		//将_year,_month,_day都初始化为1
		cout << "已调用Example" << endl;
		_year = 1;
		_month = 1;
		_day = 1;
	}
	void prin()
	{
		 cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	//创建实例
	Example E;
	//调用函数
	E.prin();

}

运行结果:

默认构造函数,我们无法指定初始值。那可不可以指定初始值呢,答案是可以的。

1.2.2 带参数的构造函数
class Example {
public:	
    Example(int year, int month, int day)
	{
		//将_year,_month,_day都初始化
		cout << "已调用Example" << endl;
		_year = year;
		_month = month;
		_day = day;
	}
	void prin()
	{
		 cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	//创建实例
	//掉用方式可以直接在创建实例的时候传参,编译器会自动调用。
	Example E(2024,6,4);
	//调用函数
	E.prin();

}

运行结果:

那么,有没有更好的呢,如果我们将之前学习的全缺省参数结合起来,你就会得到一个可传参也可不传参的构造函数。注:刚开始其实已经提到过了。

class Example {
public:
	//全缺省的构造函数
	Example(int year = 1, int month = 1, int day = 1)
	{
		cout << "已调用Example" << endl;
		_year = year;
		_month = month;
		_day = day;
	}
	void prin()
	{
		 cout << _year << "-" << _month << "-" << _day << endl;
	}
private:
	int _year;
	int _month;
	int _day;
};
int main()
{
	//创建实例
	//掉用方式可以直接在创建实例的时候传参,编译器会自动调用。
	Example E(2024,6,4);
	//调用函数
	E.prin();
	Example E1;
	E1.prin();
}

运行结果:

注:当我们提供构造函数的时候,编译器不会生成默认构造函数。

1.2.3 拷贝构造函数
#include <iostream>
using namespace std;

class MyClass {
   public:
      int x;
      MyClass(int val) : x(val) {}  // 普通构造函数
      MyClass(const MyClass &obj) {  // 拷贝构造函数
         x = obj.x;
         cout << "调用了拷贝构造函数,复制的值为:" << obj.x << endl;
      }
};

int main() {
   MyClass obj1(10);   // 调用普通构造函数
   MyClass obj2 = obj1; // 调用拷贝构造函数
   cout << "obj2 的值为:" << obj2.x << endl;
   return 0;
}

上述代码中,我们定义了一个 MyClass 类,并在其中定义了一个普通构造函数和一个拷贝构造函数。在 main() 函数中,我们首先使用普通构造函数创建了一个对象 obj1,然后使用拷贝构造函数将 obj1 的值复制给了 obj2。在这个过程中,程序会自动调用拷贝构造函数,并输出一条提示信息。

运行结果:

1.2.4 移动构造函数

移动构造函数是C++11中引入的一种特殊构造函数,用于在对象之间进行资源转移,提高程序的效率。移动构造函数可以将一个右值引用参数的资源所有权转移到一个新对象中,而不是像拷贝构造函数那样进行资源的拷贝。这在处理大量数据时尤为重要,因为资源拷贝会带来较大的开销。

class MyObject {
public:
    MyObject() { // 构造函数
        m_data = new int[1000];
        // 分配大量内存
    }
    MyObject(MyObject&& other) { // 移动构造函数
        m_data = other.m_data; // 转移资源所有权
        other.m_data = nullptr; // 清空原有资源指针
    }
    ~MyObject() { // 析构函数
        delete[] m_data;
        // 释放资源
    }
private:
    int* m_data;
};

int main() {
    MyObject obj1; // 构造对象1
    MyObject obj2(std::move(obj1)); // 移动构造对象2
    // obj1 现在已经失去了对 m_data 的所有权
    return 0;
}

在上面的代码中,我们定义了一个 MyObject 类,并实现了一个移动构造函数。在 main 函数中,我们首先通过默认的构造函数构造了一个对象 obj1,然后使用 std::move 将其转换为右值引用并传递给另一个对象 obj2 的移动构造函数中。在这个过程中,obj1 失去了对 m_data 指针所指向内存的所有权,而 obj2 获得了这个所有权。

2. 析构函数

2.1 概念

析构函数是用于在对象被删除之前的清理工作,在对象生命周期即将结束时被自动调用。(析构函数可以清理对象并且释放内存)
析构函数 ~加上类名() 进行操作,目的时清空数据,释放内存。
下面举一个示例:

#include <iostream>

class MyClass {
private:
	int* data;

public:
	MyClass() {
		data = new int[10];
		std::cout << "已调用Constructor" << std::endl;
	}

	~MyClass() {
		delete[] data;
		std::cout << "已调用Destructor" << std::endl;
	}
};

int main() {
	MyClass obj; // 创建一个 MyClass 对象

	// 在 main 函数结束时,obj 对象超出作用域,触发析构函数的调用
	return 0;
}

运行结果:

3. 每期一问

3.1 上期答案

struct Node* copyRandomList(struct Node* head) {
    if(!head)
    {
        return head;
    }
	struct Node* cur = head;
    //1.申请节点copy插入cur后面
    while(cur)
    {
        struct Node* copy = (struct Node*)malloc(sizeof(struct Node));
        copy->val = cur->val;
        struct Node* next = cur->next;
        cur->next = copy;
        copy->next = next;
        cur = next;
    }
    //2.copy中random的指针的值指向cur->next->random
    cur = head;
    while(cur)
    {
        struct Node* copy = cur->next;
        if(NULL == cur->random)
        {
            copy->random = NULL;
        }
        else
        {
            copy->random = cur->random->next;
        }
        cur = copy->next;
    }
    //3.分割拷贝链表,还原原链表
    struct Node* copyTail = NULL, *copyHead = NULL;
    cur = head;
    while(cur)
    {
        if(!copyHead && !copyTail)
        {
            copyHead = copyTail = cur->next;
        }
        else{
            copyTail->next = cur->next;
            copyTail = copyTail->next;
        }
        cur->next = copyTail->next;
        cur = cur->next;
    }
    copyTail->next = NULL;
    return copyHead;
}

本期问题:. - 力扣(LeetCode)

注:本期到这里就结束了,后面还会说到移动构造函数。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Python - OS模块+sys模块

一、OS模块基本用法&#xff1a; import osprint(os.getcwd()) # 获取当前工作目录os.chdir(data) # 改变当前脚本工作目录&#xff1b;相当于终端里面的cd命令 print(os.getcwd()) # 获取当前工作目录 运行结果&#xff1a; D:\__TC22008_VBF\FOTA-vFlash-AutoTest D:\__TC22…

Mac下载了docker,在终端使用docker命令时用不了

问题&#xff1a;在mac使用docker的时候&#xff0c;拉取docker镜像失败 原因&#xff1a;docker是需要用app使用的 &#xff0c;所以在使用的时候必须打开这个桌面端软件才可以在终端上使用docker命令&#xff01;&#xff01;&#xff01;

【企业家必看】解锁财富新机遇:二人订单共享模式

在这个充满变革与创新的时代&#xff0c;我们有幸向您介绍一种全新的商业模式——二人订单共享模式。这不仅是一次商业创新&#xff0c;更是一次财富与价值共享的革命。 终身消费&#xff0c;终身收益 只需一次499元的终身消费&#xff0c;您即可成为会员。这意味着&#xff0…

JavaScript的选择结构和循环结构

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

晋级决赛 | 璞华龙舟队:驰骋双湖展雄风,龙舟“浪”出新高度!

“金荡杯”第三届江苏省传统龙舟邀请赛 6月2日&#xff0c;“金荡杯”第三届江苏省传统龙舟邀请赛&#xff08;鹅湖站&#xff09;在风景如画的鹅湖畔火热开赛。 碧波荡漾的湖面上&#xff0c;数条龙舟犹如一条条巨龙&#xff0c;蓄势待发&#xff0c;准备在比赛中一展风采。随…

cesium 多边形加边框宽度 Polygon outlineWidth

cesium中用polygon添加多边形时&#xff0c;设置outlineWidth无效&#xff0c;常见做法是在添加polygon的同时加一个polyline&#xff0c;但是当多边形相邻两条边的角度比较小的情况下&#xff0c;这两个点的连接处有明显的交叉。 解决方案&#xff1a; 第一步&#xff1a;通过…

Chromium源码阅读:深入理解Mojo框架的设计思想,并掌握其基本用法(2)

我们继续分析Chromium的Mojo模块。 Dispatcher Dispatcher 是 Mojo IPC 系统中的一个关键概念。它是一个虚基类类&#xff08;或接口&#xff09;&#xff0c;用于实现与特定 MojoHandle 相关联的 Mojo 核心 API 调用。在 Mojo 系统中&#xff0c;应用程序通过这些 API 与各种…

Python基于车牌识别的车辆进出管理系统

目录 1、效果图2、具体内容系统流程开发工具和环境项目所需依赖包目录描述&#xff1a;启动Django服务登录账号 3、源码下载技术交流 博主介绍&#xff1a; 计算机科班人&#xff0c;全栈工程师&#xff0c;掌握C、C#、Java、Python、Android等主流编程语言&#xff0c;同时也熟…

JavaWeb5 SpringBoot+HTTP协议

Spring Spring Boot 非常快速构建应用程序&#xff0c;简化开发 &#xff08;1&#xff09;创建Springboot工程&#xff0c;勾选web开发依赖 创建好的目录&#xff0c;并将没用多余的删掉了 &#xff08;2&#xff09;定义请求处理类&#xff0c;并添加方法 创建请求处理类…

华为云DDoS攻击下的应对策略

当华为云上的服务遭遇大规模DDoS攻击导致网络流量异常&#xff0c;触发了华为云的自动防护机制&#xff0c;即所谓的“黑洞”状态时&#xff0c;服务将暂时无法访问&#xff0c;直至攻击停止或流量恢复正常。本文将探讨如何在这一情况下&#xff0c;通过引入第三方安全产品来快…

目标检测——DeepGlobe道路提取数据集

引言 亲爱的读者们&#xff0c;您是否在寻找某个特定的数据集&#xff0c;用于研究或项目实践&#xff1f;欢迎您在评论区留言&#xff0c;或者通过公众号私信告诉我&#xff0c;您想要的数据集的类型主题。小编会竭尽全力为您寻找&#xff0c;并在找到后第一时间与您分享。 …

Springboot使用webupload大文件分片上传(包含前后端源码)

Springboot使用webupload大文件分片上传&#xff08;包含源码&#xff09; 1. 实现效果1.1 分片上传效果图1.2 分片上传技术介绍 2. 分片上传前端实现2.1 什么是WebUploader&#xff1f;功能特点接口说明事件APIHook 机制 2.2 前端代码实现2.2.1&#xff08;不推荐&#xff09;…

huggingface_hub LocalEntryNotFoundErroringface

报错详细 LocalEntryNotFoundError: An error happened while trying to locate the file on the Hub and we cannot find the requested files in the local cache. Please check your connection and try again or make sure your Internet connection is on.问题说明 在…

【UML用户指南】-15-对高级结构建模-对象图

目录 1、对象图的组成 2、 对象图和类图关系 3、对对象结构建模 4、逆向工程 5、对象图构建要求 对象图对包含在类图中的事物的实例建模。 对象图显示了在某一时间点上一组对象以及它们之间的关系。 对象图用于对系统的静态设计视图或静态交互视图建模。 对某一时刻的系统…

CentOS7下快速升级至OpenSSH9.7p2安全版本

一、CentOS7服务器上编译生成OpenSSH9.3p2的RPM包 1、编译打包的shell脚本来源于该项目 https://github.com/boypt/openssh-rpms解压zip项目包 unzip openssh-rpms-main.zip -d /opt cd /opt/openssh-rpms-main/ vim pullsrc.sh 修改第23行为source ./version.env 2、sh pull…

人工智能在肿瘤细胞分类中的应用|顶刊速递·24-06-06

小罗碎碎念 推文主题——人工智能在肿瘤细胞分类中的应用。 重点关注 临床方向的同学/老师建议重点关注第四篇&第六篇文章&#xff0c;最近DNA甲基化和蛋白组学与AI的结合&#xff0c;在顶刊中出现的频率很高&#xff0c;建议思考一下能否和自己的课题结合。 工科的同学重…

全网爆火【MBTI人格测试】是如何实现的?

功能介绍 概述 MBTI人格测试是一款基于Agent Builder框架开发的智能体应用&#xff0c;旨在通过五个精心设计的问题准确分析用户的MBTI性格类型。完成测试后&#xff0c;应用将提供详细的性格分析和建议&#xff0c;帮助用户更好地理解自己的性格特点。 功能详述 1. MBTI测试…

RAG实战4-RAG过程中发生了什么?

RAG实战4-RAG过程中发生了什么&#xff1f; 在RAG实战3中我们介绍了如何追踪哪些文档片段被用于检索增强生成&#xff0c;但我们仍不知道RAG过程中到底发生了什么&#xff0c;为什么大模型能够根据检索出的文档片段进行回复&#xff1f;本文将用一个简单的例子来解释前面的问题…

Linux磁盘管理(MBR、分区表、分区、格式化)

目录 1、简单介绍 2、MBR&#xff1a; 2.1、分区表&#xff1a; 2.2、注意&#xff1a; 2.3、编号问题&#xff1a; 2.4、磁盘的命名&#xff1a; 2.5、格式化分区 1、简单介绍 1.1、track&#xff1a;磁道&#xff0c;就是磁盘上同心圆&#xff0c;从外向里&#xff0c…

Imagic: Text-Based Real Image Editing with Diffusion Models

Imagic: Text-Based Real Image Editing with Diffusion Models Bahjat Kawar, Google Research, CVPR23, Paper, Code 1. 前言 在本文中&#xff0c;我们首次展示了将复杂&#xff08;例如&#xff0c;非刚性&#xff09;基于文本的语义编辑应用于单个真实图像的能力。例如…