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

news/2025/11/13 16:53:58/文章来源:https://www.cnblogs.com/yangykaifa/p/19218737

个人主页: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.mzph.cn/news/964476.shtml

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

相关文章

Akamai 简单 记录

Akamai 简单 记录2025.11.13找到 sensor_data 的地方``` var TK7 = rB[kY()[mq(S9)].call(null, lg, KG, WF)][kY()[mq(tr)](RC(RC([])), Ax, pO)](RK7); `````` 向上搜索 RK7 RK7 = rB[kY()[mq(S9)].apply(null,…

2025年海南景区标识标牌设计公司权威推荐榜单:海口标识标牌制作/标识标牌制作/安全标识标牌设计源头公司精选

在海南自贸港建设与旅游业升级的双重推动下,景区标识标牌作为游客体验的重要载体,其专业设计与制作正成为景区建设的关键环节。 随着海南旅游市场持续回暖,景区配套设施升级需求显著增长。据行业统计数据显示,2025…

251112D. 谜题(poem)

251112D. 谜题(poem) 给定长为 \(n\) 的排列 \(a\)。有 \(k\) 次交换,每次在所有的 \(\binom n2\) 对数中随机一对交换。问最终逆序对数的期望。 但是这样还不够!有 \(q\) 次修改,将第 \(i\) 次交换改为交换给出的…

可白嫖源码---45125构建个性化智能实习匹配与综合管理平台的研究与构建(案例分析)-附源码

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

同行都在降本,你还在浪费?3招软件许可优化快速追赶!

我是Tom,一线做IT运维已经10年了,看到身边不少同行在软件许可这件事上吃亏,今天我就把我在“许可优化”这条坑上踩过的常识,毫无保留地分享出来,希望能帮到钱没少烧但还在原地踏步的你。 先说说我每次去帮人做系统…

【CSS】background-size 属性详解

【CSS】background-size 属性详解【CSS】background-size 属性详解原创【CSS】background-size 属性详解-CSDN博客于 2024-09-23 11:30:52 发布1.8w 阅读 32 33CC 4.0 BY-SA版权文章标签:#css#前端#node.js#javascrip…

Redis分布式锁:从“能用”到“好用”,中间差了多少细节?

redis分布式锁安全吗? 1、为什么需要分布式锁与分布式锁对应的是【单机锁】,在写多线程时,避免同时操作一个共享变量产生数据问题,通常会使用一把锁来【互斥】,以确保共享变量的正确性,使用范围是在同一个进程中…

为什么你的JavaScript代码总是出bug?这5个隐藏陷阱太坑了!

🧑‍💻 写在开头 点赞 + 收藏 === 学会🤣🤣🤣你是不是经常遇到这样的情况:明明代码看起来没问题,一运行就各种报错?或者测试时好好的,上线后用户反馈bug不断?更气人的是,有时候改了一个小问题,结果引…

[电调]AM32电调调参系列 —— Complementary PWM参数的作用与分析

[电调]AM32电调调参系列 —— Complementary PWM参数的作用与分析https://blog.csdn.net/qq_39312146/article/details/153827884在AM32固件中,​​Complementary PWM(互补PWM)​​ 的选择对电调的性能、效率和发热…

Zabbix监控mysl数据库配置

用mysql自带的模板,可以监控如下内容:OPS(增删改查)、mysql请求流量带宽,mysql响应流量带宽,最后会附上相应的监控图! 一、编写脚本 check_mysql.sh vi /usr/local/zabbix/share/check_mysql.sh !/bin/bash ---…

Java 线程同步与线程间通信

Java 线程同步与线程间通信 线程同步概述 核心问题:竞争状态与线程安全 当多个线程同时访问共享资源(临界资源)时,可能导致资源数据被破坏,这种现象称为竞争状态。若一个类的对象在多线程环境中不会引发竞争状态,…

2025年惠州高端中医馆品牌权威推荐榜单:老中医问诊/代煎中药/老中医调理身体品牌精选

在健康惠州战略推进下,高端中医馆已从单纯的诊疗服务向健康管理、特色理疗、文化传承等多元化方向发展,为市民提供全方位中医药服务。 随着居民健康消费水平升级和中医文化复兴,惠州高端中医馆市场正经历从“量变”…

HarmonyOS ArkTS卡片开发:多种方式实现卡片信息刷新

在移动应用生态中,卡片作为重要信息的快捷展示形式,极大地提升了用户体验。HarmonyOS的ArkTS卡片开发为开发者提供了强大的工具,本文将基于CardInfoRefresh示例项目,深入解析ArkTS卡片开发的核心原理与实践。1. Ar…

可视化图解算法68:数组中出现次数超过一半的数字

对于LeetCode数据结构与算法,我们总结了一套【可视化+图解】方法,依据此方法来解决相关问题,算法变得易于理解,写出来的代码可读性高也不容易出错。1.题目 描述 给一个长度为 n 的数组,数组中有一个数字出现的次数…

2025年惠州线下媒体公司权威推荐榜单:楼宇视频广告/社区广告/社区媒体广告源头公司精选

在信息过载的数字时代,线下媒体以其真实的场景触达和稳定的传播效果,正重获品牌方的青睐。 惠州线下媒体市场近年来保持稳定发展态势。据行业调研数据显示,社区媒体广告市场年增长率保持在15%左右,预计2025年惠州地…

题解:P9052 [PA 2021] Areny

好题,但是也没有那么难,感觉难度很大一部分在于读懂题。 题意:给出一个有向图,保证每个点都有一个出度且不为自环,现在求出对于每个 \(1\le k\le n\),满足以下条件的 \((A,B)\) 对有多少个。\(1\le A\le k,A\not…

Copula函数的参数估计与拟合

Copula函数的参数估计与拟合 Copula函数是描述随机变量间相关结构的强大工具,它将边缘分布与变量间的依赖结构分离建模。详细介绍Copula函数的参数估计与拟合方法 Copula理论基础 Copula函数定义 Copula函数是一个多元…

深度学习进阶(八)——AI 操作系统的雏形:AgentOS、Devin 与多智能体协作 - 实践

深度学习进阶(八)——AI 操作系统的雏形:AgentOS、Devin 与多智能体协作 - 实践pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; fon…

服务保护

服务降级、熔断 服务雪崩:一个服务失败,导致整条链路的服务都失败的情景 服务降级:服务降级是服务自我保护机制的一种方式,或者保护下游服务的一种方式,用于确保服务不会受请求突增的影响变得不可用,确保服务不会…