C++奇迹之旅:构造函数

请添加图片描述

文章目录

  • 📝类的6个默认成员函数
  • 🌠 构造函数
    • 🌉 概念
    • 🌉特性
    • 🌉三种默认构造函数
  • 🚩总结


📝类的6个默认成员函数

如果一个类中什么成员都没有,简称为空类
空类中真的什么都没有吗?并不是,任何类在什么都不写时,编译器会自动生成以下6个默认成员函数。默认成员函数:用户没有显式实现,编译器会生成的成员函数称为默认成员函数。

class Date {};

🌠 构造函数

🌉 概念

对于以下Date类:

class Date
{
public:void Init(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;
};
int main()
{Date d1;d1.Init(2006, 6, 27);d1.Print();Date d2;d2.Init(2022, 7, 6);d2.Print();return 0;
}

对于Date类,可以通过 Init 公有方法给对象设置日期,但如果每次创建对象时都调用该方法设置信息,未免有点麻烦,那能否在对象创建时,就将信息设置进去呢?

构造函数是一个特殊的成员函数名字与类名相同,创建类类型对象时由编译器自动调用,以保证每个数据成员都有 一个合适的初始值,并且在对象整个生命周期内只调用一次

🌉特性

构造函数是特殊的成员函数,需要注意的是,构造函数虽然名称叫构造,但是构造函数的主要任务并不是开空间创建对象,而是初始化对象
其特征如下:

  1. 函数名类名相同。
  2. 无返回值。
  3. 对象实例化时编译器自动调用对应的构造函数。
  4. 构造函数可以重载。
    构造函数可以重载,主要分为两类:
  • 无参构造函数
class Date
{
public://无参构造函数Date(){}void print(){cout << _year << _month << _day << endl;}private:int _year;int _month;int _day;
};int main()
{Date d1;//调用无参构造函数d1.print();return 0;
}

在这里插入图片描述
这样的无参构造,依然是初始化为随机数。
注意:如果无参构造函数创建对象时,对象后面不用跟括号,否则就成了函数声明

在这里插入图片描述

  • 带参构造函数
class Date
{
public://带参构造函数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;
};int main()
{Date d2(2024, 4, 15);//调用带参构造函数//带参是要直接在后面加括号的d2.print();return 0;
}

调用带参构造函数,带参是要直接在后面加括号的
在这里插入图片描述

两者结合,构成重载关系:在这里插入图片描述

  1. 如果类中没有显式定义构造函数,则C++编译器会自动生成一个无参的默认构造函数,一旦用户显式定义编译器将不再生成。

没有显示构造函数在这里插入图片描述
代码可以通过编译,因为编译器生成了一个无参的默认构造函数,对象实例化,编译器调用自动调用默认构造函数,这多好啊,都不用自己实现,但是使用编译器实现的默认构造函数出来初始化的数据是随机值,不是0,这就有点麻烦了。
在这里插入图片描述

而如果我们显示实现呢?

class Date
{
public://如果用户显式定义了构造函数,编译器将不再生成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;
};int main()
{Date d2(2024, 4, 15);//调用带参构造函数//带参是要直接在后面加括号的d2.print();return 0;
}

一旦自己显式定义任何构造函数,编译器将不再生成。
在这里插入图片描述

  1. 关于编译器生成的默认成员函数,很多童鞋会有疑惑:不实现构造函数的情况下,编译器会生成默认的构造函数。但是看起来默认构造函数又没什么用?d对象调用了编译器生成的默认构造函数,但是d对象_year/_month/_day,依旧是随机值。也就说在这里编译器生成的默认构造函数并没有什么用??(有些编译器可能会初始化为0,但是C++标准并没有规定)

解答:C++把类型分成内置类型(基本类型)和自定义类型。内置类型就是语言提供的数据类型,如:int/char...,自定义类型就是我们使用class/struct/union等自己定义的类型,看看
下面的程序,就会发现编译器生成默认的构造函数会对自定类型成员_t调用的它的默认构造函数。

让让我们看看以下这个代码:

class A
{
public:A(){_a = 0;cout << "A()" << endl;}private:int _a;
};class Date
{
public:// 我们没写,有没有构造函数?有->编译器自动生成// 内置类型/基本类型 int/char/double.../指针 // 自定义类型       class/struct...// 编译器自动生成构造函数,对于内置类型成员变量,没有规定要不要做处理!(有些编译器会处理)//                       对于自定义类型成员变量才会调用他的无参构造void Print(){cout << _year << "-" << _month << "-" << _day << endl;}private:int _year; // 年int _month; // 月int _day; // 日A _aa;
};int main()
{Date d1;d1.Print();return 0;
}

开始运行图:这些都是编译器给的随机值在这里插入图片描述
结束运行图:编译器对自定义类型成员变量去调用它的无参构造,对内置类型不做处理,当你编译器跑出了随机值或者0,也不要奇怪,不同编译器不同实现。
在这里插入图片描述
总结:如果在Time这个类中如果没有Time()成员函数初始化赋值,那继续像类Date这样自定义一个类型,那他会继续调用下一个自定义类的默认构造函数,如果后面的类还有,那么他就会不断查找下去,直到最后内置类型有初始化了,或者说没有自定义类型了。
总结一句话:自定义类型的终点还是内置类型

我们没写,有没有构造函数?有,编译器自动生成,内置类型/基本类型 int/char/double.../指针 ,对于自定义类型 class/struct...编译器自动生成构造函数,对于内置类型成员变量,没有规定要不要做处理!(有些编译器会处理)
对于自定义类型成员变量才会调用他的无参构造
我们再看这个代码:

class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year;int _month;int _day;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}

在这里插入图片描述
对于内置数据类型的成员变量,它们在默认构造函数中不会被初始化,所以它们的值是未定义的,也就是随机值。而对于自定义类型的成员变量,编译器会调用它们的默认构造函数来初始化,但是如果这个自定义类型也没有定义默认构造函数,那么它的成员变量也会是未定义的值,像Time()构造函数中,我们给他的成员初始化为0。

注意:C++11中针对内置类型不初始化的缺陷,有打了补丁,即:内置类型成员变量在类中声明可以给默认值。

class Time
{
public:Time(){cout << "Time()" << endl;_hour = 0;_minute = 0;_second = 0;}
private:int _hour;int _minute;int _second;
};
class Date
{
private:// 基本类型(内置类型)int _year = 1970;int _month = 1;int _day = 1;// 自定义类型Time _t;
};
int main()
{Date d;return 0;
}

这个给默认值不叫初始化,叫做给缺省值,因为在类中,内置类型里的这些是声明,不是定义,没有分配内存空间,所以不能赋值初始化。
在这里插入图片描述
小提示:
这里当我们调试时,按下F11它是直接跳转到time()的成员内部,那中间的内置类型不过一遍吗?因此我们再稍微改改,看看以下代码:

class Time
{
public:Time(int hour = 1, int minute = 1, int second = 1){cout << "Time()" << endl;_hour = hour;_minute = minute;_second = second;}
private:int _hour = 9;int _minute = 8;int _second = 7;
};

动态调试图:
请添加图片描述

这里我们看到他并不是跳过内置类型,然后直接调用自定义类型,真正过程是略过一下内置类型,然后在构造函数中用参数覆盖了内置类型的值。

那自动生成的构造函数意义何在?编译器生成的默认构造函数确实没有什么用,因为它并不会初始化类的成员变量。

如果在Time这个类中如果没有Time()成员函数初始化赋值,那继续像类Date这样自定义一个类型,那他会继续调用下一个自定义类的默认构造函数,如果后面的类还有,那么他就会不断查找下去,直到最后内置类型有初始化了,或者说没有自定义类型了。
总结一句话:自定义类型的终点还是内置类型

🌉三种默认构造函数

无参的构造函数和全缺省的构造函数都称为默认构造函数,并且默认构造函数只能有一个。注意:无参构造函数全缺省构造函数我们没写编译器默认生成的构造函数,都可以认为是默认构造函数

class Date
{
public:Date(){_year = 1900;_month = 1;_day = 1;}Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}
private:int _year;int _month;int _day;
};
// 以下测试函数能通过编译吗?
int Test()
{Date d1;return 0;
}

在这里插入图片描述

这段代码不能通过编译。编译器会报错 “C2668: ‘Date::Date’: 对重载函数的调用不明确”。
出现这个错误的原因是,在 main() 函数中,当创建 Date d1 对象时,编译器无法确定应该调用哪个构造函数。
这是因为 Date() 构造函数和 Date(int, int, int) 构造函数都可以匹配 Date d1 的初始化,编译器无法确定应该调用哪个构造函数,产生调用歧义。因此我们可以使用一个即可,用的比较多的是这种全缺省构造函数:

Date(int year = 1900, int month = 1, int day = 1){_year = year;_month = month;_day = day;}

实践中总结:
1、一般情况构造函数都需要我们自己显示的去实现
2、只有少数情况下可以让编译器自动生成构造函数
类似MyQueue,成员全是自定义类型
在这里插入图片描述


🚩总结

请添加图片描述

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

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

相关文章

【重磅开源】一款可以生成SpringBoot+Vue代码的轻量级项目

基于SpringBootVue3开发的轻量级快速开发脚手架 &#x1f341;项目简介 一款通用的前、后端项目模板 一款快速开发管理系统的项目 一款可以生成SpringBootVue代码的项目 一款持续迭代的开源项目 一个程序员的心血合集 度过严寒&#xff0c;终有春日&#xff…

Nginx内存池相关源码剖析(一)总览

剖析nginx的内存池源码&#xff0c;讲解原理实现以及该内存池设计的应用场景 介绍 Nginx内存池是Nginx为了优化内存管理而引入的一种机制。在Nginx中&#xff0c;每个层级&#xff08;如模板、TCP连接、HTTP请求等&#xff09;都会创建一个内存池进行内存管理。当这些层级的…

Linux下redis的安装过程与配置详细教程【5.0.5为例子】

Linux下redis的安装过程与配置方法【5.0.5为例子】 下载redis redis下载地址 https://download.redis.io/releases/ 也可以自行去官网下载 提示&#xff1a;此处安装的为redis-5.05的版本 上传redis安装包(我的安装目录为/data/tool/redis-5.0.5) 创建目录/data/local/tool并…

Day20-【Java SE高级】单元测试 反射 注解 动态代理

一、单元测试 就是针对最小的功能单元(方法)&#xff0c;编写测试代码对其进行正确性测试。 1. 咱们之前是如何进行单元测试的?有啥问题? 只能在main方法编写测试代码&#xff0c;去调用其他方法进行测试。无法实现自动化测试&#xff0c;一个方法测试失败&#xff0c;可能…

Day 23 669. 修剪二叉搜索树 108.将有序数组转换为二叉搜索树 538.把二叉搜索树转换为累加树 总结篇

修剪二叉搜索树 给定一个二叉搜索树&#xff0c;同时给定最小边界L 和最大边界 R。通过修剪二叉搜索树&#xff0c;使得所有节点的值在[L, R]中 (R>L) 。你可能需要改变树的根节点&#xff0c;所以结果应当返回修剪好的二叉搜索树的新的根节点。 ​ 最直接的想法&#xff0…

最强解释!Python 包的依赖管理,有解了!

之前一直比较抵触用 Python &#xff0c;很大一部分原因是觉得 Python 项目的环境管理比较混乱。Node.js 有 Npm 包管理工具&#xff0c;通过 package.json 配置项目依赖&#xff0c;最多再通过 nvm 来进行环境切换&#xff1b;Java 有 Maven Gradle 来进行包管理和项目依赖配置…

今天刷两题(day2)

题目一&#xff1a;最长公共前缀 题目描述&#xff1a; 给你一个大小为 n的字符串数组 strs &#xff0c;其中包含n个字符串 , 编写一个函数来查找字符串数组中的最长公共前缀&#xff0c;返回这个公共前缀。输入输出描述&#xff1a; 输入&#xff1a;"abca","…

MyBatis 源码分析 - SQL 的执行过程

MyBatis 源码分析 - SQL 的执行过程 * 本文速览 本篇文章较为详细的介绍了 MyBatis 执行 SQL 的过程。该过程本身比较复杂&#xff0c;牵涉到的技术点比较多。包括但不限于 Mapper 接口代理类的生成、接口方法的解析、SQL 语句的解析、运行时参数的绑定、查询结果自动映射、延…

C++ 秋招必知必会(数据结构与算法:下)

20. 二叉树的定义与操作 二叉树&#xff08;binary tree&#xff09;是一种非线性数据结构&#xff0c;代表着祖先与后代之间的派生关系&#xff0c;体现着“一分为二”的分治逻辑 与链表类似&#xff0c;二叉树的基本单元是节点&#xff0c;每个节点包含&#xff1a;值、左子…

MYSQL5.7详细安装步骤

MYSQL5.7详细安装步骤&#xff1a; 0、更换yum源 1、打开 mirrors.aliyun.com&#xff0c;选择centos的系统&#xff0c;点击帮助 2、执行命令&#xff1a;yum install wget -y 3、改变某些文件的名称 mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base…

储能的全生命周期成本即平准化度电成本的计算方法及python实践

1. 平准化度电成本&#xff08;LCOE&#xff09;是一种衡量电力项目经济性的指标 LCOE&#xff08;Levelized Cost of Energy,&#xff09;的概念最早由美国国家可再生能源实验室&#xff08;NREL&#xff09;在1995年提出&#xff0c;它是通过将一个项目生命周期内的所有成本…

黑马头条项目结构

微服务架构具有许多优点&#xff0c;其中一些主要优点包括&#xff1a; 松耦合性&#xff1a;每个微服务都是独立的&#xff0c;可以独立部署、独立扩展和独立更新&#xff0c;这种松耦合性使得系统更加灵活&#xff0c;易于维护和演化。 技术多样性&#xff1a;由于每个微服务…

基于springboot实现知识管理系统项目【项目源码+论文说明】

基于springboot实现知识管理系统演示 摘要 随着信息互联网信息的飞速发展&#xff0c;无纸化作业变成了一种趋势&#xff0c;针对这个问题开发一个专门适应师生作业交流形式的网站。本文介绍了知识管理系统的开发全过程。通过分析企业对于知识管理系统的需求&#xff0c;创建了…

2024年4月13日美团春招实习试题【第四题:乘积因子数】-题目+题解+在线评测【二分】

2024年4月13日美团春招实习试题【第四题:乘积因子数】-题目题解在线评测【二分】 题目描述&#xff1a;输入描述输出描述样例 解题思路一&#xff1a;python解题思路二&#xff1a;c解题思路三&#xff1a;0 题目描述&#xff1a; 塔子哥拿到了一个数组&#xff0c;她有q次查询…

HTTP/1.1特性总结

优点 【简单&#xff0c;灵活和易于扩展&#xff0c;应用广泛和跨平台】 1.简单&#xff1a; http基本的报文格式就是headerbody&#xff0c;头部信息也是key-value简单的文本形式&#xff0c;易于理解&#xff0c;降低了学习和使用的门槛 2.灵活和易于扩展&#xff1a; &…

Redis 配置与使用 (Linux 虚拟机Windows客户端)

Centos7 安装Redis详细教程 - JcongJason - 博客园 (cnblogs.com) 安装 下载redis安装包并解压 # 下载&#xff0c;我是在root下执行的下载&#xff0c;所以我的下载目录为&#xff1a;/root/redis-5.0.5&#xff0c;这里按照自己的实际情况调整 wget https://download.redi…

Methoxy PEG Glutaric Acid可以改善物质的溶解性、稳定性和生物相容性

【试剂详情】 英文名称 mPEG-GA&#xff0c;mPEG-Glutaric Acid&#xff0c; Methoxy PEG GA&#xff0c; Methoxy PEG Glutaric Acid 中文名称 聚乙二醇单甲醚戊二酸&#xff0c; 甲氧基-聚乙二醇-戊二酸 外观性状 由分子量决定&#xff0c;固体或液体 分子量 400&…

浅谈Java的synchronized 锁以及synchronized 的锁升级

在Java中&#xff0c;synchronized关键字用于实现线程间的同步&#xff0c;确保同一时刻只有一个线程能够访问被同步的代码块或方法。当一个线程获得synchronized锁定后&#xff0c;其他试图访问同一锁的线程将被阻塞&#xff0c;直到锁被释放。 synchronized锁有两种基本形式…

为什么说六西格玛培训公司是企业问题的“终结者”

随着六西格玛管理方法的走红&#xff0c;六西格玛培训公司应运而生&#xff0c;致力于帮助企业解决各种核心问题&#xff0c;实现业绩的飞跃。那么&#xff0c;六西格玛培训公司究竟能为企业解决哪些问题&#xff1f;又为什么说六西格玛培训公司是企业问题的“终结者”呢&#…

第47期 | GPTSecurity周报

GPTSecurity是一个涵盖了前沿学术研究和实践经验分享的社区&#xff0c;集成了生成预训练Transformer&#xff08;GPT&#xff09;、人工智能生成内容&#xff08;AIGC&#xff09;以及大语言模型&#xff08;LLM&#xff09;等安全领域应用的知识。在这里&#xff0c;您可以找…