【C++指南】类和对象(二):类的默认成员函数——全面剖析 :构造函数

           💓 博客主页:倔强的石头的CSDN主页 

           📝Gitee主页:倔强的石头的gitee主页

            ⏩ 文章专栏:《C++指南》

                                  期待您的关注

 

47f09392526c71b5885ec838a3ea7ffe.gif

 

阅读本篇文章之前,你需要具备的前置知识:类和对象的基础

点击下方链接

【C++指南】类和对象(一):类和对象的定义和使用 基础讲解-CSDN博客

目录

引言

默认成员函数的介绍

深入解析C++类的构造函数

构造函数的概念

构造函数的特性

默认构造函数

编译器默认生成的构造函数的行为

 

需要自己实现构造函数的情况

  初始化列表

构造函数与析构函数的关系

结尾


 

引言

在C++编程中,类的设计是实现面向对象编程(OOP)理念的核心。类不仅封装了数据(即属性)和操作这些数据的方法(即成员函数),还通过特定的成员函数——默认成员函数,管理着对象的生命周期和状态变化。

这些默认成员函数,包括构造函数、析构函数、拷贝构造函数以及赋值运算符重载函数,是C++类设计中不可或缺的部分,它们定义了对象如何被创建、销毁、复制以及赋值。

 

  • 构造函数是对象生命周期的起点,负责初始化对象的内部状态。
  • 析构函数则标志着对象生命周期的结束,用于执行必要的清理工作,确保资源得到妥善管理。
  • 拷贝构造函数赋值运算符重载函数则与对象的复制行为紧密相关,它们定义了如何创建一个对象的副本以及如何将一个对象的状态复制到另一个对象上。 

 

理解并正确实现这些默认成员函数对于编写健壮、可维护的C++代码至关重要。它们不仅影响着对象的性能,还直接关系到程序的安全性和正确性。然而,这些函数的自动生成和默认行为往往无法满足所有情况的需求,特别是在涉及资源管理、动态内存分配或复杂数据结构时。因此,作为C++开发者,我们有必要深入了解这些默认成员函数的工作原理,学会在适当的时候自定义它们以满足特定的需求。

 

本文旨在详细讲解C++中类的默认成员函数,包括构造函数、析构函数、拷贝构造函数、赋值运算符重载函数以及取地址运算符重载函数的基本概念、使用场景、实现细节和注意事项。

通过本文的学习,读者将能够更加熟练地运用这些默认成员函数,编写出更加高效、安全、易于维护的C++代码。

 

注:

因默认构造函数内容较多,限于篇幅分成系列文章发布:

 

可点击下方链接阅读:

【C++指南】类和对象(三):类的默认成员函数——全面剖析析构函数-CSDN博客

【C++指南】类和对象(四):类的默认成员函数——全面剖析 拷贝构造函数-CSDN博客

【C++指南】类和对象(五):类的默认成员函数——全面剖析 赋值运算符重载函数-CSDN博客

 

 

默认成员函数的介绍

在C++中,当定义一个类时,编译器会自动为该类生成几个特殊的成员函数,如果开发者没有显式定义它们的话。这些函数被称为默认成员函数特殊成员函数。它们对于类的对象管理至关重要,包括对象的创建、销毁、复制以及赋值操作。

以下是几个关键的默认成员函数:

  1. 构造函数(Constructor):用于在创建对象时初始化对象。
  2. 析构函数(Destructor):用于在对象生命周期结束时执行清理工作。
  3. 拷贝构造函数(Copy Constructor):用于创建一个新对象,作为已存在对象的副本。
  4. 赋值运算符重载函数(Assignment Operator Overloading):用于实现对象之间的赋值操作。
  5. 取地址运算符重载函数:实际上,C++标准中并没有直接为取地址运算符(&)提供默认的重载机制,因为对象的地址总是由编译器自动处理。但理解何时需要重载其他运算符(如*,对于指针类)对于完整理解运算符重载是有帮助的。这里我们将重点放在前四个默认成员函数上。

 

类的默认成员函数虽然看起来复杂,但其实一点也不简单。 掌握默认成员函数对于后期的学习是非常重要的基础,想要理解透彻,除了默认成员函数本身的特性,还应该从两个方面入手:

  • 第⼀:我们不写时,编译器默认生成的函数行为是什么,是否满足我们的需求。
  • 第⼆:编译器默认⽣成的函数不满足我们的需求,我们需要自己实现,那么如何自己实现

 

深入解析C++类的构造函数

构造函数的概念

C++中的构造函数是一种特殊的成员函数,用于在创建对象时初始化对象的数据成员。构造函数的主要任务是在对象实例化时,根据提供的参数(如果有的话)来设置对象的初始状态。要注意构造函数的主要任务并 不是开空间创建对象(我们常使用的局部对象是栈帧创建时,空间就开好了),而是对象实例化时初始化。 对象构造函数的名字与类名完全相同,并且没有返回类型(连void也不允许)。

 

构造函数的特性

  1. 名字与类名相同:构造函数的名字必须与类名完全一致,包括大小写。
  2. 无返回类型:构造函数不能有任何返回类型,包括void
  3. 自动调用:在创建对象时,编译器会自动调用相应的构造函数。
  4. 可以重载:一个类可以有多个构造函数,只要它们的参数列表不同,就可以实现重载。
  5. 默认构造函数:如果程序员没有显式定义任何构造函数,编译器会自动生成一个默认的无参构造函数。但一旦定义了任何构造函数,编译器就不会再自动生成默认构造函数。
  6. 构造初始化列表:构造函数可以使用初始化列表来给成员变量赋值,这种方式比在构造函数体内赋值更高效。

默认构造函数

默认构造函数是没有参数或者所有参数都有默认值的构造函数。如果类中没有显式定义任何构造函数,编译器会自动生成一个默认的无参构造函数。

无参构造函数、全缺省构造函数、我们不写构造时编译器默认⽣成的构造函数,都叫做默认构造函 数。但是这三个函数有且只有⼀个存在,不能同时存在。

无参构造函数和全缺省构造函数虽然构成 函数重载,但是调⽤时会存在歧义。要注意很多人会认为默认构造函数是编译器默认⽣成那个叫 默认构造,实际上⽆参构造函数、全缺省构造函数也是默认构造,总结⼀下就是不传实参就可以调 ⽤的构造就叫默认构造

示例: 

class Date
{
public:// 1.无参构造函数/*Date(){_year = 1;_month = 1;_day = 1;}*///2.全缺省构造函数Date(int year = 1, int month = 1, int day = 1){_year = year;_month = month;_day = day;}// 3.带参构造函数// Date(int year, int month, int day)//{//    _year = year;//    _month = month;//    _day = day;//}void Print(){cout << _year << "/" << _month << "/" << _day << endl;}
private:int _year;int _month;int _day;
};

比如上述类的定义中:我们定义了三个构造函数,其中第一个、第二个以及不写构造函数时编译器默认生成的构造函数,都属于默认构造函数

一般情况下,建议写一个全缺省的构造函数,这样就可以应对各种传参的情况

第三个构造函数——带参的构造函数,就属于正常的构造函数 

 

再次强调:

无参构造函数、全缺省构造函数、我们不写构造时编译器默认⽣成的构造函数,这三个函数有且只有⼀个存在,不能同时存在。

当自己实现了构造函数之后,编译器就不会生成默认构造函数,而且无参构造函数和全缺省构造函数虽然构成 函数重载,但是调用时会存在歧义,两个构造函数只能存在一个,否则就会报错。

 

编译器默认生成的构造函数的行为

我们不写,编译器默认⽣成的构造

  • 对内置类型成员变量的初始化没有要求,也就是说是否初始 化是不确定的,看编译器。
  • 对于⾃定义类型成员变量,要求调⽤这个成员变量的默认构造函数初始化。如果这个成员变量,没有默认构造函数,那么就会报错,我们要初始化这个成员变量,需要⽤ 初始化列表才能解决

 

需要自己实现构造函数的情况

结论: 大多数情况下,构造函数都需要自己实现

比如:

  1. 类中存在内置类型,需要在构造时初始化赋值(这种情况多数存在)
  2. 类初始化需要申请资源,比如通过指针指向一块动态申请的空间

少数情况下不需要写构造函数:

比如:当类中的成员变量全部为自定义类型(类类型),会自动调用成员变量的默认构造函数,这时不需要自己实现构造函数

 

  初始化列表

构造函数初始化列表是构造函数体执行之前执行的一部分,用于初始化成员变量。它使用冒号:分隔参数列表和成员初始化列表。使用初始化列表比在构造函数体内赋值通常更高效,因为它直接调用成员的构造函数(如果有的话)。

MyClass(int x) : member(x) {} // 使用初始化列表初始化member
class ClassName {  
public:  ClassName(parameters) : member1(initializer1), member2(initializer2), ... {  // 构造函数体  }  private:  MemberType1 member1;  MemberType2 member2;  // 其他成员变量  
};

 构造函数初始化列表的规则

  • 语法理解上初始化列表可以认为是每个成员变量定义 初始化的地方
  • 引⽤成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进⾏初始 化,否则会编译报错
  1. 对于常量成员变量,它们必须在构造函数的初始化列表中初始化,因为常量一旦被定义就不能被修改。
  2. 对于引用成员变量,它们也必须在初始化列表中初始化,因为引用一旦被定义就必须指向一个有效的对象。
  3. 对于某些类型的对象(如没有默认构造函数的类类型对象),它们可能需要在初始化列表中通过特定的值或另一个对象的拷贝来初始化。
  • C++11⽀持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显⽰在初始化列表初始化的 成员使⽤的
  • 初始化列表中按照成员变量在类中声明顺序进⾏初始化,跟成员在初始化列表出现的的先后顺序⽆ 关。建议声明顺序和初始化列表顺序保持⼀致

 

初始化列表的使用示例

#include <iostream>  
#include <string>  // 定义一个简单的类Point,表示二维空间中的一个点  
class Point {  
private:  int x; // x坐标  int y; // y坐标  public:  // 构造函数使用初始化列表来初始化成员变量x和y  Point(int xVal, int yVal) : x(xVal), y(yVal) {  // 构造函数体可以为空,因为成员变量已经在初始化列表中初始化了  std::cout << "Point constructed at (" << x << ", " << y << ")" << std::endl;  }  // 一个方法来打印点的坐标  void print() const {  std::cout << "Point is at (" << x << ", " << y << ")" << std::endl;  }  
};  int main() {  // 创建一个Point对象,并使用初始化列表来设置x和y的值  Point p1(5, 10);  // 调用print方法来打印点的坐标  p1.print();  return 0;  
}

 

 

构造函数的执行顺序参考图

a3d80ef6151a459ba196beda1feb8936.png

 

构造函数与析构函数的关系

  • 构造函数和析构函数是对象生命周期的两端。
  • 构造函数负责初始化对象,而析构函数负责清理对象所占用的资源。
  • 一旦对象被创建,其构造函数就会被调用一次,并且在对象的整个生命周期内不会被再次调用。
  • 而析构函数则在对象的生命周期结束时被调用,确保所有资源得到释放,避免内存泄漏等问题。

 

结尾

构造函数是C++面向对象编程中的核心概念之一,它决定了对象如何被初始化和配置。了解构造函数的工作原理、类型、初始化列表以及其与析构函数的关系,对于编写高效、安全、易于维护的C++代码至关重要。通过合理利用构造函数,我们可以更加灵活地控制对象的创建和初始化过程,为程序的稳定性和性能打下坚实的基础

 

 

 

 

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

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

相关文章

顶会论文复现:PROVING TEST SET CONTAMINATION IN BLACK BOX LANGUAGE MODELS

文章目录 1 资料2 我的总结3 复现源码首先你需要有gpt的api接口安装&#xff1a;数据集执行指令源码 4 结果 1 资料 我复现的源码:https://github.com/Whiffe/test_set_contamination 官网源码&#xff1a;https://github.com/tatsu-lab/test_set_contamination 论文&#x…

Java实体对象转换利器MapStruct详解

概述 现在的JAVA项目多数采用分层结构&#xff0c;参考《阿里巴巴JAVA开发手册》。 分层之后&#xff0c;每一层都有自己的领域模型&#xff0c;即不同类型的 Bean&#xff1a;  DO &#xff08; Data Object &#xff09; &#xff1a;与数据库表结构一一对应&#xff0c;…

游戏盾是如何解决游戏行业攻击问题

随着游戏行业的迅猛发展&#xff0c;其高额的利润和激烈的市场竞争吸引了众多企业和创业者的目光。然而&#xff0c;这一行业也面临着前所未有的业务和安全挑战&#xff0c;尤其是DDoS&#xff08;分布式拒绝服务&#xff09;攻击&#xff0c;已经成为游戏行业的一大威胁。今天…

C语言基础(10)之指针(2)

在上一篇文章中我们谈到了指针&#xff0c;并给老铁们讲解了什么是指针、指针类型、野指针以及指针运算等知识。在这篇文章中小编将继续带大家了解指针的相关知识点。 1. 指针和数组 指针和数组之间又能有什么联系呢&#xff1f;在谈这个之前&#xff0c;我们先来讲讲指针和数…

Android15车载音频之Virtualbox中QACT实时调试(八十八)

简介: CSDN博客专家、《Android系统多媒体进阶实战》一书作者 新书发布:《Android系统多媒体进阶实战》🚀 优质专栏: Audio工程师进阶系列【原创干货持续更新中……】🚀 优质专栏: 多媒体系统工程师系列【原创干货持续更新中……】🚀 优质视频课程:AAOS车载系统+…

微信小程序开发-调试及配置文件介绍

一&#xff0c;隐藏控制台系统日志 在小程序开发中&#xff0c;如果你想要隐藏控制台中的系统日志&#xff0c;可以通过以下步骤进行操作&#xff1a; 打开小程序的开发工具。在开发工具的控制台(Console)中&#xff0c;找到你想要隐藏的系统日志。右键点击该系统日志条目。在…

MySQL连接查询:外连接

先看我的表结构 dept表 emp表 外连接分为 1.左外连接 2.右外连接 1.左外连接 基本语法 select 字段列表 FORM 表1 LEFT [OUTER] JOIN 表2 ON 条件;例子&#xff1a;查询emp表的所有数据&#xff0c;和对应部门的员工信息&#xff08;左外连接&#xff09; select e.*, d.n…

利士策分享,旅游是否要舟车劳顿才能尽兴?

利士策分享&#xff0c;旅游是否要舟车劳顿才能尽兴&#xff1f; 国庆假期&#xff0c;当夜幕降临&#xff0c;城市灯火阑珊&#xff0c;一场关于美食与等待的较量悄然上演。 李女士在北京天坛公园附近餐厅的等位经历——前方1053桌的壮观景象&#xff0c;不仅让人咋舌&#xf…

信息学奥赛复赛复习14-CSP-J2021-03网络连接-字符串处理、数据类型溢出、数据结构Map、find函数、substr函数

PDF文档回复:20241007 1 P7911 [CSP-J 2021] 网络连接 [题目描述] TCP/IP 协议是网络通信领域的一项重要协议。今天你的任务&#xff0c;就是尝试利用这个协议&#xff0c;还原一个简化后的网络连接场景。 在本问题中&#xff0c;计算机分为两大类&#xff1a;服务机&#x…

3. BBP系列运动控制板(飞控板)简介

3.1. 概述 Bread Board Pilot(简称BBP) 是在积累了前期 Single Pilot 及 PH7 飞控板大量设计及使用经验的基础上&#xff0c;全新基于PH47代码框架开发的高灵活性&#xff0c; 高性能&#xff0c; 超低成本的最新一代飞控板设计。 目前&#xff0c;因为其使用便捷灵活&#xf…

Hallo部署指南

一、介绍 Hallo是由复旦大学、百度公司、苏黎世联邦理工学院和南京大学的研究人员共同提出的一个AI对口型肖像图像动画技术&#xff0c;可基于语音音频输入来驱动生成逼真且动态的肖像图像视频。 该框架采用了基于扩散的生成模型和分层音频驱动视觉合成模块&#xff0c;提高了…

【AI知识点】正则化(Regularization)

正则化&#xff08;Regularization&#xff09; 是机器学习和统计学中的一种技术&#xff0c;用于防止模型过拟合。在训练模型时&#xff0c;模型可能会过度拟合训练数据&#xff0c;导致在新数据上的表现较差。正则化通过在优化过程中引入额外的约束或惩罚项&#xff0c;使模型…

【开发心得】筑梦上海:项目风云录(6)

目录 会海跳槽 票务开启 漂泊在外的日子 未完待续 会海跳槽 随着时刻表的出炉&#xff0c;意味着大规模的界面开发逐步进入正规。项目组里陆陆续续引进了8个人&#xff0c;最多的时候&#xff0c;同时有10个人在现场。“松工”为我们准备的办公室坐的满满当当&#xff0c;…

Maven 高级之分模块设计与继承、聚合

在软件开发中&#xff0c;随着项目规模的扩大&#xff0c;代码量和复杂度不断增加&#xff0c;传统的一体化开发模式逐渐暴露出诸多问题。为了解决这些问题&#xff0c;模块化开发应运而生&#xff0c;而 Maven 正是模块化开发的利器&#xff0c;它提供的继承和聚合机制为构建和…

wc命令:统计文本行数、单词数、字节数

一、命令简介 ​wc​&#xff08;word count&#xff09;是一个在类 Unix 系统中常用的命令行工具&#xff0c;用于统计文本文件的 行数​、单词数 ​和 字节数​。 ​​ ‍ 二、命令参数 ​wc​ 命令的基本语法如下&#xff1a; wc [选项] 文件选项&#xff1a; ​-c​…

当管理遇上AI,工作效率翻了3倍!

最近这段时间&#xff0c;很多企业都开始降薪、裁员。 在降本增效的大背景下&#xff0c;企业但凡有什么大动作&#xff0c;压力往往都会转嫁到管理者的身上。 一方面&#xff0c;要调大家的状态&#xff0c;处理团队中的各种琐事&#xff1b;另一方面&#xff0c;要及时响应…

【ESP32】Arduino开发 | Timer定时器+定时器闹钟例程

有关定时器外设的详细介绍在ESP-IDF的对应文章中&#xff0c;跳转栏目目录可以找到。 1. API 1.1 启动定时器 hw_timer_t * timerBegin(uint8_t timer, uint16_t divider, bool countUp); timer&#xff1a;定时器序号&#xff08;ESP32有4个硬件定时器&#xff0c;所以可填序…

SpringBoot赋能旅游管理:系统设计与实现

第三章 系统分析 3.1可行性分析 对所有的系统来说&#xff0c;都有可能会受到时间和空间上的制约。所以&#xff0c;我们在设计每一个项目的时候&#xff0c;必须对该系统实行可行性分析&#xff0c;这样不但能够降低项目的危害&#xff0c;还能改降低人力、物力和财力的损耗。…

【CKA】十六、监控Pod度量指标

16、监控Pod度量指标 1. 考题内容&#xff1a; 2. 答题思路&#xff1a; 题目意思是&#xff1a;找出label有namecpu-user的CPU最高的Pod&#xff0c;然后把它的名字写在已经存在的 /opt/KUTR00401/KUTR00401.txt文件里 3. 官网地址&#xff1a; https://kubernetes.io/zh-…

LeetCode 54 Spiral Matrix 解题思路和python代码

题目&#xff1a; Given an m x n matrix, return all elements of the matrix in spiral order. Example 1: Input: matrix [[1,2,3],[4,5,6],[7,8,9]] Output: [1,2,3,6,9,8,7,4,5] Example 2: Input: matrix [[1,2,3,4],[5,6,7,8],[9,10,11,12]] Output: [1,2,3,4,8,1…