C++构造和折构函数详解,超详细!

news2024/11/26 2:39:29

个人主页:PingdiGuo_guo

收录专栏:C++干货专栏

大家龙年好呀,今天我们来学习一下C++构造函数和折构函数。

文章目录

1.构造函数

1.1构造函数的概念

1.2构造函数的思想

1.3构造函数的特点

1.4构造函数的作用

1.5构造函数的操作

1.6构造函数的分类

1.6.1默认构造函数(Default Constructor)

1.6.2带参数构造函数(Parameterized Constructor)

1.6.3拷贝构造函数(Copy Constructor)

1.6.4移动构造函数(Move Constructor)

1.6.5委托构造函数(Delegating Constructor)

1.6.6虚拟构造函数(Virtual Constructor)

1.7构造函数的练习

1.7.1题目

1.7.2步骤

1.7.3代码

2.折构函数

2.1折构函数的概念

2.2折构函数的思想

2.3折构函数的特点

2.4折构函数的作用

2.5折构函数的操作

2.6折构函数的分类

2.6.1默认析构函数

2.6.2有特定目的的析构函数

3.构造函数和折构函数的利弊

3.1利

3.2弊

4.总结


1.构造函数

1.1构造函数的概念

构造函数是C++中的特殊成员函数,用于初始化新创建的对象。当一个类的对象被声明并实例化时,构造函数自动被调用。它的主要作用是确保对象在其生命周期开始时就处于有效状态。

1.2构造函数的思想

构造函数的思想是在创建对象时,用于初始化对象的成员变量和执行其他必要的操作。构造函数在对象创建时自动调用,不需要手动调用。构造函数的主要目的是确保对象被正确地初始化,以便在使用对象时不会出现未定义的行为或错误。

1.3构造函数的特点

1.构造函数的名称与类名称相同,并且没有返回类型(包括void类型),包括默认构造函数和带参数的构造函数。

2.构造函数可以重载,即在同一个类中可以定义多个具有不同参数列表的构造函数。

3.构造函数可以带有参数,在创建对象时,可以根据传递的参数值来初始化对象的成员变量。

4.构造函数可以进行一些初始化操作,例如分配内存、调用其他对象的构造函数等。

5.构造函数可以被继承,子类可以调用父类的构造函数来初始化父类的成员变量。

1.4构造函数的作用

1.对象的初始化:构造函数用于初始化对象的成员变量,确保对象在创建时具有正确的初始状态。

2.分配和初始化成员变量:构造函数可以分配并初始化类的成员变量,以便在对象创建时设置默认值或特定的初始状态。

3.进行必要的前置操作:构造函数可以执行一些必要的前置操作,例如打开文件、连接数据库等。

4.为对象分配内存:构造函数负责为对象分配内存空间,这通常发生在通过 new 运算符创建对象时。

5.链接到其他对象或资源:构造函数可以将对象链接到其他对象或资源,以便对象能够使用这些外部资源。

6.初始化对象的状态:构造函数可以设置对象的初始状态,例如设置指针成员变量为 null、设置计数器为 0 等。

7.执行其他必要的操作:构造函数还可以执行其他与对象创建相关的必要操作,如申请资源、注册回调函数等。

8.为派生类提供基类的初始化:在派生类的构造函数中,可以通过调用基类的构造函数来初始化继承自基类的成员变量。

1.5构造函数的操作

1. 定义类结构:
 

class Book {
private:
char* title; // 私有成员变量,用于存储动态分配的标题字符串

public:
// 构造函数声明
Book(const char* t);
};



2. 实现构造函数:
在类外部实现构造函数,它负责接收一个 C 风格字符串并将其复制到动态分配的内存中。
 

Book::Book(const char* t) {
// 计算字符串长度(包括终止符 '\0')
size_t len = strlen(t) + 1;

// 动态分配内存
title = new char[len];

// 使用标准库函数strcpy复制字符串
strcpy(title, t);
}




3. 构造函数操作:
当创建 Book 对象时,构造函数会被自动调用:
 

int main() {
Book book("The Title of the Book"); // 这里调用了构造函数
// ...
return 0;
}


在上述代码中,当我们创建 book对象时,传入的字符串 "The Title of the Book"将被复制到通过 new分配的内存空间中。

1.6构造函数的分类

构造函数可以分为以下几种分类:

1.6.1默认构造函数(Default Constructor)

如果一个类没有定义任何构造函数,那么编译器会自动生成一个默认构造函数。默认构造函数没有任何参数,并且不进行任何初始化操作。

class MyClass {
public:
    // 默认构造函数
    MyClass() {
        // 进行初始化操作
    }
};

int main() {
    // 创建一个对象,调用默认构造函数
    MyClass obj;
    return 0;
}

1.6.2带参数构造函数(Parameterized Constructor)

带参数构造函数接收一定数量和类型的参数,用于对对象的成员变量进行初始化。通过传递不同的参数值,可以创建具有不同初始状态的对象。

class MyClass {
public:
    // 带参数构造函数
    MyClass(int value) {
        // 进行初始化操作,使用参数value对对象进行初始化
    }
};

int main() {
    // 创建一个对象,调用带参数构造函数
    MyClass obj(10);
    return 0;
}

1.6.3拷贝构造函数(Copy Constructor)

拷贝构造函数是一种特殊的构造函数,用于创建一个新对象,并将现有对象的值复制到新对象中。拷贝构造函数通常用于对象之间的值传递或对象的复制。

class MyClass {
public:
    // 拷贝构造函数
    MyClass(const MyClass& other) {
        // 进行拷贝操作,将other对象的值复制到当前对象中
    }
};

int main() {
    // 创建一个对象,调用拷贝构造函数
    MyClass obj1;
    MyClass obj2 = obj1;  // 或者 MyClass obj2(obj1);
    return 0;
}

1.6.4移动构造函数(Move Constructor)

移动构造函数是C++11引入的一种特殊构造函数,用于将右值引用参数转移或"窃取"其资源,而不是进行复制。移动构造函数可以提高程序的效率和性能。

class MyClass {
public:
    // 移动构造函数
    MyClass(MyClass&& other) {
        // 进行移动操作,将other对象的资源移动到当前对象中
    }
};

int main() {
    // 创建一个对象,调用移动构造函数
    MyClass obj1;
    MyClass obj2 = std::move(obj1);  // 或者 MyClass obj2(std::move(obj1));
    return 0;
}

1.6.5委托构造函数(Delegating Constructor)

委托构造函数是C++11引入的一种特殊构造函数,它允许一个构造函数调用同一个类的另一个构造函数,以避免代码冗余。

class MyClass {
public:
    // 默认构造函数
    MyClass() : MyClass(0) {
        // 委托给带参数的构造函数
    }
    
    // 带参数构造函数
    MyClass(int value) {
        // 进行初始化操作,使用参数value对对象进行初始化
    }
};

int main() {
    // 创建一个对象,调用默认构造函数
    MyClass obj;
    return 0;
}

1.6.6虚拟构造函数(Virtual Constructor)

虚拟构造函数是一种在基类中声明的构造函数,用于在派生类中动态创建基类对象。虚拟构造函数是通过在基类中声明纯虚函数来实现的。

class Base {
public:
    // 虚拟构造函数
    virtual Base* clone() const {
        return new Base(*this);
    }
    
    // 其他成员函数和数据成员
};

class Derived : public Base {
public:
    // 虚拟构造函数的重写
    virtual Derived* clone() const {
        return new Derived(*this);
    }
    
    // 其他成员函数和数据成员
};

int main() {
    // 创建一个派生类对象,调用虚拟构造函数的重写
    Base* basePtr = new Derived();
    Base* copy = basePtr->clone();
    
    // 其他操作
    
    delete basePtr;
    delete copy;
    return 0;
}

1.7构造函数的练习

1.7.1题目

设计并实现一个 Person类,其中包含姓名和年龄属性,并编写一个自定义构造函数来初始化这些属性。

1.7.2步骤

1. 定义 `Person` 类结构,声明私有成员变量。
2. 编写构造函数,接受姓名(字符串类型)和年龄(整型)作为参数。
3. 在构造函数内,对传入的参数进行有效性检查(可选)。
4. 将传入的参数值赋给对应的成员变量。

1.7.3代码

// Step 1: 定义 Person 类
class Person {
private:
    std::string name;
    int age;

public:
    // Step 2: 编写构造函数
    Person(const std::string& n, int a) {
        // Step 3: 参数有效性检查(例如年龄应该大于0)
        if (a < 0) {
            throw std::invalid_argument("Age must be positive.");
        }

        // Step 4: 赋值给成员变量
        name = n;
        age = a;
    }

    // 其他成员函数...
};

// 使用构造函数创建一个 Person 对象
int main() {
    Person person("John Doe", 30);
    return 0;
}

2.折构函数

2.1折构函数的概念

析构函数是C++中另一种特殊的成员函数,它与构造函数相反,在对象生命周期结束时(例如对象的作用域结束或者delete一个动态分配的对象时)自动调用。析构函数主要用于清理工作,如释放内存、关闭文件等。

2.2折构函数的思想

析构函数是一种特殊的成员函数,在对象销毁时自动调用,用于释放对象所占用的资源。

析构函数与构造函数相对应,构造函数用于对象的初始化,而析构函数用于对象的清理与释放。

2.3折构函数的特点

1.析构函数没有参数,且没有返回值。

2.析构函数的名称与类名相同,前面加上波浪号(~)作为前缀。

3.只能有一个析构函数,且不能被继承或重载。

4.析构函数不能被显式地调用,不能被重载。

5.对象销毁时,析构函数会自动调用,从而完成对象的销毁和资源的释放。

6.析构函数按照对象的创建顺序的逆序调用,即先创建的对象后销毁。

2.4折构函数的作用

1.释放动态分配的内存或资源。

2.关闭打开的文件、数据库连接等。

3.清理对象中的临时数据和状态。

4.执行其他清理和释放操作。

2.5折构函数的操作

1. 定义析构函数:
在类内部声明析构函数,它将在 Book 对象生命周期结束时(例如,超出作用域或显式销毁)自动调用。
 

class Book {
// ...
public:
// 析构函数声明
~Book();
};



2. 实现析构函数:
在类外部实现析构函数,它负责释放之前构造函数中动态分配的内存。
 

Book::~Book() {
// 检查指针是否已经分配过内存
if (title != nullptr) {
delete[] title; // 释放内存
title = nullptr; // 设置为 nullptr 防止悬挂指针
}
}



3. 析构函数操作:
析构函数的操作是自动的,不需要程序员显式调用。当 Book对象离开其作用域时,析构函数会自动执行。
 

int main() {
{
Book book("The Title of the Book"); // 创建对象时构造函数被调用
} // 这里 book 作用域结束,析构函数将被自动调用,释放 title 的内存
return 0;
}


在上述代码中,当 book 对象超出作用域时,析构函数将被调用,释放之前为 title分配的内存。这样就确保了程序不会出现内存泄漏的问题。

2.6折构函数的分类

析构函数的分类主要分为默认析构函数和有特定目的的析构函数。

2.6.1默认析构函数

如果在类中没有显式定义析构函数,编译器会自动生成一个默认的析构函数。默认析构函数会自动释放对象占用的内存,但不执行任何其他操作。


 

class MyClass {
public:
    // 构造函数
    MyClass() {
        // 构造函数的代码
    }
    // 默认析构函数
    ~MyClass() {
        // 自动生成的析构函数,无需显式定义
    }
};

2.6.2有特定目的的析构函数

有些情况下,需要在对象销毁时执行特定的清理操作,例如释放资源、关闭文件、释放动态分配的内存等。这时可以自定义析构函数,并在其中编写相应的清理代码。


 

class MyClass {
private:
    int* ptr; // 动态分配的内存指针

public:
    // 构造函数
    MyClass() {
        ptr = new int[10]; // 动态分配内存
    }

    // 有特定目的的析构函数
    ~MyClass() {
        delete[] ptr; // 释放动态分配的内存
    }
};

在上述代码中,我们定义了一个具有特定目的的析构函数,用于释放动态分配的内存。当对象销毁时,析构函数会自动被调用,执行内存释放操作。

需要注意的是,每个类只能有一个析构函数,不能重载析构函数。析构函数没有参数,也没有返回值。析构函数的名称与类名称相同,并在前面加上波浪线(~)作为标识。

使用析构函数可以确保在对象生命周期结束时进行清理工作,避免内存泄漏和资源浪费的问题。同时,通过自定义析构函数,可以根据具体需求执行特定的清理操作。

3.构造函数和折构函数的利弊

3.1利


- 构造函数确保了对象从一开始就处于已知的良好状态。
- 析构函数提供了自动资源管理机制,减少内存泄漏和其他资源泄露的风险。



3.2弊


- 如果构造函数或析构函数内部逻辑复杂,可能影响程序性能或增加错误的可能性。
- 构造函数抛出异常会导致未初始化的对象,而析构函数如果在异常处理期间抛出异常,则可能导致程序行为不可预测。

4.总结

本篇博客到这里就结束了,感谢大家的支持与观看,如果有好的建议欢迎留言,谢谢大家啦!

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

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

相关文章

电子电器架构 —— 对车载软件开发新阶段的愿景

电子电器架构 —— 对车载软件开发新阶段的愿景 我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师(Wechat:gongkenan2013)。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 本就是小人物,输了就是输了,不要在意别人怎么看自己。江湖一碗茶,喝…

使用C++从零开始,自己写一个MiniWeb

第一步&#xff1a;新建项目 1、打开VS点击创建新项目 2、选择空项目并点下一步&#xff08;切记不能选错项目类型&#xff09; 3、填写项目名称和路径&#xff0c;点击创建即可 新建好后项目是这样的比较干净 4、右击源文件&#xff0c;点击添加&#xff0c;新建http.cpp文件…

【华为云】容灾方案两地三中心实践理论

应用上云之后&#xff0c;如何进行数据可靠性以及业务连续性的保障是非常关键的&#xff0c;通过华为云云上两地三中心方案了解相关方案认证地址&#xff1a;https://connect.huaweicloud.com/courses/learn/course-v1:HuaweiXCBUCNXI057Self-paced/about当前内容为灾备常见理论…

代码随想录 Leetcode55. 跳跃游戏

题目&#xff1a; 代码(首刷自解 2024年2月9日&#xff09;&#xff1a; class Solution { public:bool canJump(vector<int>& nums) {int noz 0;for (int i nums.size() - 2; i > 0; --i) {if (nums[i] 0) {noz;continue;} else {if (nums[i] > noz) noz …

【Java八股面试系列】JVM-class文件结构

Class文件结构总结 根据 Java 虚拟机规范&#xff0c;Class 文件通过 ClassFile 定义&#xff0c;有点类似 C 语言的结构体。我们之前都是使用javap命令来对字节码文件进行反编译查看的&#xff0c;我们可以使用WinHex软件&#xff08;Mac平台可以使用010 Editor&#xff09;来…

假期day7

设计qq界面 代码 ui->lab1->setPixmap(QPixmap(":/pictrue/denglu.webp"));ui->lab1->setScaledContents(true);ui->lab2->setPixmap(QPixmap(":/pictrue/passwd.jpg"));ui->lab2->setScaledContents(true);ui->lab3->setP…

Elasticsearch:使用查询规则(query rules)进行搜索

在之前的文章 “Elasticsearch 8.10 中引入查询规则 - query rules”&#xff0c;我们详述了如何使用 query rules 来进行搜索。这个交互式笔记本将向你介绍如何使用官方 Elasticsearch Python 客户端来使用查询规则。 你将使用 query rules API 将查询规则存储在 Elasticsearc…

Java奠基】对象数组练习

目录 商品对象信息获取 商品对象信息输入 商品对象信息计算 商品对象信息统计 学生数据管理实现 商品对象信息获取 题目要求是这样的&#xff1a; 定义数组存储3个商品对象。 商品的属性&#xff1a;商品的id&#xff0c;名字&#xff0c;价格&#xff0c;库存。 创建三个…

Pytorch卷积层原理和示例 nn.Conv1d卷积 nn.Conv2d卷积

内容列表 一&#xff0c;前提 二&#xff0c;卷积层原理 1.概念 2.作用 3. 卷积过程 三&#xff0c;nn.conv1d 1&#xff0c;函数定义&#xff1a; 2, 参数说明: 3,代码: 4, 分析计算过程 四&#xff0c;nn.conv2d 1, 函数定义 2, 参数&#xff1a; 3, 代码 4, 分析计算过程 …

Netty应用(七) 之 Handler Netty服务端编程总结

目录 15.Handler 15.1 handler的分类 15.1.1 按照方向划分 15.1.2 handler的结构 15.2 输入方向ChannelInboundHandlerAdapter 15.2.1 输出方向Handler的顺序 15.2.2 多个输入方向Handler之间的数据传递 15.2.2.1 handler消失了 15.2.2.2 手动编写netty提供的new Strin…

一个查看armv8系统寄存器-值-含义的方式

找到解压后的SysReg_xml_v86A-2019-12目录 wget https://developer.arm.com/-/media/developer/products/architecture/armv8-a-architecture/2019-12/SysReg_xml_v86A-2019-12.tar.gz wget https://developer.arm.com/-/media/developer/products/architecture/armv8-a-archi…

(已解决)将overleaf上的文章paper上传到arxiv上遇到的问题。

文章目录 前言初级问题后续问题 前言 首先说一点&#xff0c;将paper的pdf文件直接上传arxiv是不行的&#xff0c;arxiv要求我们要上传源文件&#xff0c;所以才这么麻烦。 初级问题 首先上传文件之后有可能会在下面这个界面出现问题&#xff0c;这里一般都比较常见的问题&a…

『运维备忘录』之 HTTP 响应状态码速查

运维人员不仅要熟悉操作系统、服务器、网络等只是&#xff0c;甚至对于开发相关的也要有所了解。很多运维工作者可能一时半会记不住那么多命令、代码、方法、原理或者用法等等。这里我将结合自身工作&#xff0c;持续给大家更新运维工作所需要接触到的知识点&#xff0c;希望大…

java学习07---综合练习

飞机票 1.需求: 机票价格按照淡季旺季、头等舱和经济舱收费、输入机票原价、月份和头等舱或经济舱。 按照如下规则计算机票价格&#xff1a;旺季&#xff08;5-10月&#xff09;头等舱9折&#xff0c;经济舱8.5折&#xff0c;淡季&#xff08;11月到来年4月&#xff09;头等舱7…

[C#] 如何使用ScottPlot.WPF在WPF桌面程序中绘制图表

什么是ScottPlot.WPF&#xff1f; ScottPlot.WPF 是一个开源的数据可视化库&#xff0c;用于在 WPF 应用程序中创建高品质的绘图和图表。它是基于 ScottPlot 库的 WPF 版本&#xff0c;提供了简单易用的 API&#xff0c;使开发人员能够通过简单的代码创建各种类型的图表&#…

【项目技术点总结之三】使用Java生成复杂好看的word或pdf报告的解决方案

前言 项目中往往会遇到需要生成报告的场景&#xff0c;不管是简单报告还是复杂报告&#xff0c;其实都需要找很多资料去尝试&#xff0c;本文会提出几种个人完美解决报告生成的解决方案&#xff0c;而且会提出几个失败但是能生成报告的设想&#xff0c;当然都是踩过坑的&#…

Peter算法小课堂—背包问题

我们已经学过好久好久的动态规划了&#xff0c;动态规划_Peter Pan was right的博客-CSDN博客 那么&#xff0c;我用一张图片来概括一下背包问题。 大家有可能比较疑惑&#xff0c;优化决策怎么优化呢&#xff1f;答案是&#xff0c;滚动数组&#xff0c;一个神秘而简单的东西…

java nio零拷贝

零拷贝是一种计算机执行IO操作的优化技术&#xff0c;其核心目标是减少数据拷贝次数&#xff0c;从而提高系统性能。它主要体现在以下几个方面&#xff1a; 1. **定义与原理**&#xff1a;零拷贝字面上的意思包括“零”和“拷贝”。其中&#xff0c;“拷贝”是指数据从一个存储…

《21天精通IPv4 to IPv6》第3天:IPv6地址配置——如何为不同的系统配置IPv6?

博主猫头虎的技术世界 &#x1f31f; 欢迎来到猫头虎的博客 — 探索技术的无限可能&#xff01; 专栏链接&#xff1a; &#x1f517; 精选专栏&#xff1a; 《面试题大全》 — 面试准备的宝典&#xff01;《IDEA开发秘籍》 — 提升你的IDEA技能&#xff01;《100天精通鸿蒙》 …

SpringCloud-Nacos服务分级存储模型

Nacos 服务分级存储模型是 Nacos 存储服务注册信息和配置信息的核心模型之一。它通过将服务和配置信息按照不同级别进行存储&#xff0c;实现了信息的灵活管理和快速检索&#xff0c;为微服务架构下的服务发现和配置管理提供了高效、可靠的支持。本文将对 Nacos 服务分级存储模…