C++构造函数

article/2025/9/14 19:52:49

文章目录

  • 1 构造函数的定义及特征
  • 2 默认构造函数
    • 2.1 合成的默认构造函数
      • 2.1.1 默认初始化
      • 2.1.2 合成的默认构造函数初始化类成员变量的规则
      • 2.1.3 有些场合不能使用合成的默认构造函数
    • 2.2 全缺省的默认构造函数(参数都为默认实参的构造函数)
  • 3 构造函数初始化列表
    • 3.1 初始化列表的书写方式
    • 3.2 为什么使用初始化列表?

1 构造函数的定义及特征

构造函数是类的一种特殊成员函数,其主要作用是对类的成员进行初始化,保证每个类成员都有一个合适的初始值。

构造函数有以下特征

  • 函数名与类名一致
  • 没有返回值
  • 对象实例化时自动调用对应的构造函数
  • 支持函数重载

构造函数语法:类名(){}

需要注意的是, 没有返回值和返回值为空是两码事。返回值为空指的是该函数有返回值,其中返回值为void类型。而支持重载则说明,在一个类中,可以同时存在多个构造函数。

在代码段1中,People类提供了两个构造函数,其中第一个是无参构造函数,第二个是有参构造函数。在test函数中创建对象时,father调用的是无参构造函数,而son调用的有参构造函数,说明构造函数重载为对象的实例化提供了多种初始化方式,而对象实例化时自动调用对应的构造函数,保证了对象一定可以被初始化。

代码段1:

class People
{
public://无参构造函数 People(){} = //有参构造函数People(int age, std::string sex, std::string name){_age = age;_sex = sex;_name = name;}
private:int _age;std::string _sex = "男"; //C++11新标准规定,可以为数据成员提供一个类内初始值。//创建对象时,类内初始值用于初始化数据成员stf::string _name;
};void test()
{People father;       //不能写成People father(),否则会认为是函数的声明;People son(5, "男", "张三");
}

2 默认构造函数

默认构造函数是不用传参就可以调用的构造函数,其主要有三种:

  1. 在我们没有显式地定义类的构造函数时,编译器会自动提供一个构造函数,称为合成的默认构造函数
  2. 我们自己定义的无参构造函数,如代码1中的无参构造函数。
  3. 我们自己定义的全缺省的构造函数。

2.1 合成的默认构造函数

2.1.1 默认初始化

在讲合成的默认构造函数之前,需要先了解默认初始化

如果定义变量时没有指定初值,则变量会被默认初始化,赋予一个默认值。在C++中,变量有内置类型和自定义类型,内置类型如int、float、char等,而自定义类型是用class、struct、union自己定义的类型。变量的默认值是什么,取决于其变量类型

在代码段1中,People类中的_age变量为内置类型,如果调用无参构造进行初始化,该变量将不被初始化。在VS2019编译器中,报出如下警告:
在这里插入图片描述

执行之后,从监视窗口我们可以获知对象father和son的初始化结果,如下图:

在这里插入图片描述

可以看出,对象father的_age在初始化后,依然为随机值,也就是说_age并未初始化。而father的_sex被初始化为"男",是因为我们为_sex提供了类内初始值。C++11标准规定,可以为数据成员提供一个类内初始值,创建对象时,类内初始值用于初始化数据成员。father的_name初始化后为空串。C++中,string类规定若没有指定初始值,则默认初始化为空串

一个未初始化的内置类型变量的值是未定义的,如果对该变量进行拷贝或者以其他形式来访问,可能会导致错误。

2.1.2 合成的默认构造函数初始化类成员变量的规则

我们先来看一段代码:

代码段2

 class Cube{private:int _length;int _width;int _height;};void test(){Cube c1;}

该代码段定义了一个Cube类,其成员变量都是私有的int类型,初始化前后的值如下面两图所示。

初始化前:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-EfjQXHFl-1628063908686)(C:\Users\Chenxu Gong\AppData\Roaming\Typora\typora-user-images\image-20210526013320882.png)]

初始化后:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-08aPw4Wr-1628063908687)(C:\Users\Chenxu Gong\AppData\Roaming\Typora\typora-user-images\image-20210526013347470.png)]

可以发现,初始化前后数值都是随机值。那难道默认的构造函数不能有效初始化成员变量,其根本没有任何作用

答案是否定的。

根据我们在2.1.1中所述,默认初始化时,变量的默认值取决于变量类型。在Cube类中,三个成员变量均为int型,变量不会被初始化。如果成员变量中的类型是某种自定义类型,效果则完全不一样,且看代码段3。

代码段3

class People
{
public://参数都为默认实参的构造函数,详见2.2People(int age = 22, std::string sex = "female", std::string name = "Sefanie"){_age = age;_sex = sex;_name = name;}
private:int _age;std::string _sex;std::string _name;
};class Family
{
private:People mother;People Father;People Son;
};int main()
{Family fa;return 0;
}

我们创建了一个Family类,其中有三个成员变量,三个成员变量均为People类,在创建对象fa后,其三个成员变量均被初始化。我们从监视窗口可以获知,fa的三个成员变量均得到有效初始化。这是因为Family类的合成的默认构造函数调用了People类的默认构造函数(1.2.2中将讲述),从而实现了三个成员变量的有效初始化、

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6WmMeA0Y-1628063908688)(C:\Users\Chenxu Gong\AppData\Roaming\Typora\typora-user-images\image-20210527160643957.png)]

当类内变量为默认类型时,合成的默认构造函数按照如下规则进行初始化:

  1. 如果有类内初始值,则用它来初始化成员变量
  2. 否则执行默认初始化

当类内变量为自定义类型,且该自定义类型存在默认构造函数时,通过调用成员变量的默认构造函数来实现成员变量的初始化。

2.1.3 有些场合不能使用合成的默认构造函数

当类没有声明任何成员变量时,编译器才会提供合成的默认构造函数,然而在以下场合,不推荐使用合成的默认构造函数:

  • 类内存在内置类型或者复合类型(如数组和指针),且未提供类内初始值时。此时成员变量将不会被初始化,使用未初始化的变量可能会造成不可预计的后果。
  • 合成的默认构造函数是通过调用该自定义类型的默认构造函数来初始化类成员的,当类内存在自定义类型且该自定义类型没有默认构造函数时,编译器无法初始化该成员。若我们将代码段3改为代码段4,编译器将会报错。

代码段4

class People
{
public://此处是和代码3的唯一区别,即少了默认实参,此时People不再有默认构造函数,该代码段将报错People(int age, std::string sex, std::string name){_age = age;_sex = sex;_name = name;}
private:int _age;std::string _sex;std::string _name;
};class Family
{
private:People mother;People Father;People Son;
};int main()
{Family fa;return 0;
}

2.2 全缺省的默认构造函数(参数都为默认实参的构造函数)

在代码段3中,Family类的构造函数中,每个参数都有默认实参。根据我们在2.1.3中的描述,若类内存在自定义类型的成员变量,合成的默认构造函数必须通过调用这个成员变量的默认构造函数来实现对其的初始化。如果该成员变量不存在默认构造函数,编译器将报错。

而实际上,代码段3并未报错,也就是说,当构造函数的所有参数都有默认实参时,该构造函数也是默认构造函数。

在大多数情况下,我们都要自己写构造函数,推荐使用全缺省的方式来初始化成员变量,这样能适应大多数场景

3 构造函数初始化列表

3.1 初始化列表的书写方式

构造函数的唯一目的就是为数据成员赋初值,因此在实际应用中,构造函数的函数体往往用以下的方式来书写。我们将代码段3的People类修改如下:

代码段5

class People
{
public://原始版本的构造函数//People(int age = 22, std::string sex = "female", std::string name = "Sefanie")//{//    _age = age;//    _sex = sex;//    _name = name;//}//初始化列表版本的构造函数People(int age = 22, std::string sex = "female", std::string name = "Sefanie"):_age(age),_sex(sex),_name(name){}
private:int _age;std::string _sex;std::string _name;
};

在这个定义中,在冒号和花括号之间出现了新的部分,花括号内为空实现,这个新出现的部分称为构造函数的初始化列表。其重要作用是为新创建的对象的几个成员变量赋初值。

语法:构造函数():属性1(值1),属性2(值2)... {}

为了巩固初始化列表的写法,我们再来看一个例子

代码段6

class Date
{
public://_month和_day都初始化为1,_year用传入的参数进行初始化Date(int year):_year(year),_month(1),_day(1){}//_year, _month, _day都用传入的参数进行初始化Date(int year, int month, int day) :_year(year), _month(month), _day(day) {}
private:int _year;int _month;int _day;
};

3.2 为什么使用初始化列表?

在代码段1,3,4中的构造函数,是以赋值的方式实现构造函数的,而在代码段4,5中,是以初始化的方式实现构造函数的。如果没有在构造函数的初始化列表这种显式地初始化成员,那么在进入函数体之前,会先进行默认初始化,函数体内再进行赋值操作。

赋值的方式和初始化的方式与底层效率有关,前者是先初始化后赋值,而后者是直接初始化数据成员的。

其次,**如果类数据成员是const类型或者引用,必须将其初始化,而不能在函数体内才赋值。**因为const就表明该成员变量是只读属性,因此函数体内是无法改变const属性的成员变量的,而引用定义的时候,就需要初始化,如下例:

代码段7

class A
{
public:A(int i);
private:int _i;const int _j;int& _k;
};//错误示例
//A::A(int i)
//{
//    _i = i;
//    _j = i; //函数体内无法修改const,错误
//    _k = _i; //引用应该在定义时或者初始化列表中进行初始化,错误
//}//正确
A::A(int i) :_i(i), _j(i), _k(_i) {}

如果按照代码段7中的错误示例书写,在VS2019中将会报如下错误。也就是说,初始化const和引用类型的变量的唯一机会就是在初始化列表中构造初始值。
在这里插入图片描述


http://chatgpt.dhexx.cn/article/9VoYQsZX.shtml

相关文章

C++ 构造函数详解

目录 0. 什么是构造函数 1. 默认构造函数 2. 一般构造函数 3. 拷贝构造函数 4. 转换构造函数 5. 移动构造函数 0. 什么是构造函数 在定义类的成员函数的时候,一般的成员函数与普通的全局函数没有太大的区别,在定义函数的时候都需要说明要返回的类…

【C++要笑着学】类的默认成员函数详解 | 构造函数 | 析构函数 | 构造拷贝函数

🔥 🔥 🔥 🔥 🔥 火速猛戳订阅 👉 《C要笑着学》 👈 趣味教学博客 🔥 🔥 🔥 🔥 🔥 [ 本篇博客热榜最高排名:7 ] 写在前…

JSF 文档参考

转自:http://blog.csdn.net/ontheway20/article/details/38532241 A4J 用户指南 目录 1. 介绍 2. 开始使用Ajax4jsf 环境需求 下载Ajax4jsf 安装 简单的 AJAX Echo 项目 JSP 页面 数据 Bean faces-config.xml Web.xml 部署 3. Ajax4jsf 框架的基本概念 介绍 结构概…

IDEA 2020.2 部署JSF项目

目录 一、用Glassfish部署JSF项目 1、下载glassfish 2、配置glassfish环境变量 3、修改jdk环境变量 4、测试glassfish是否可以正常启动 5、在IDEA中创建一个JSF项目 6.问题:部分标签元素无法显示 二、用tomcat部署JSF项目 1、新建项目或者模块,…

JSF教程(1)——简介 + HelloWorld

在写第一个HelloWorld之前先来宏观的了解一下JSF,也许你之前使用过Struts(1或者2),SpringMVC,甚至于直接采用JSPServelet开发过web层。JSF与这些最大的不同是JSF是基于一种以组件为中心的用户界面(UI&#…

JSF程式

概述: jsf使用spring的依赖注入的思想使得页面和业务逻辑更好的分离开来,页面与页面的跳转,逻辑关系,页面与后台不同的beans的对应和操作都是通过faces-config.xml文件来说明和配置。对程序员的要求不高,页面程序员可…

谈谈京东的服务框架JSF

谈谈京东的服务框架 最近由于在实习期间接触到了京东的自研服务框架JSF,简称“杰夫”,目前我写的一些新功能里面调用的下游接口就是杰夫提供的。现有有很多高效的服务框架,如阿里巴巴的Dubbo配合Apache的ZooKeeper,那么为什么京东…

JSF 转换与验证

在本文中,我们将介绍 JSF 转换和验证框架的概念,它比您所想的要容易使用得多,也灵活得多。 首先我们将介绍应用于 JSF 生命周期的转换和验证过程,然后展示一个简单的 JSF 应用程序中的默认转换和验证过程。接着将展示如何创建和插…

JSF----------基础知识初解

初次学习JSF,对其基础进行了一些学习与整理。 JSF(JavaServer Faces)它是一个基于服务器端组件的用户界面框架。 它用于开发Web应用程序。 它提供了一个定义良好的编程模型,由丰富的API和标签库组成。最新版本JSF 2使用Facelets作为其默认模板系统。 它是用Java编写…

JSF详解

1. 结构: a) 结构图: b) 说明:JSF以MVC模式为基础,与Struts不同,JSF的目标是希望以一个与Swing相类似的方式来开发网页,因此,从JSF的结构图当中,他的核心…

JSF框架整理(一)

一、框架简介 JavaServer Faces (JSF) 是一种用于构建Java Web 应用程序的标准框架,它提供了一种以组件为中心的用户界面(UI)构建方法,从而简化了Java服务器端应用程序的开发。 典型的JSF应用程序包含下列部分: 一组J…

JSF简介

JSF简介 一、 什么是 JSF : JavaServer Faces (JSF) 是一种用于构建 Web 应用程序的新标准 Java 框架。它提供了一种以组件为中心来开发 Java Web 用户界面的方法,从而简化了开发。 JavaServer Faces于2004年三月1.0版正式提出,清楚的将Web应…

JSF概述

1. JSF简洁 JSF是一种以组件为中心,遵循MVC设计模式的一种框架。 Web引用程序开发人员划分:网页设计人员应用程序设计人员UI组件设计人员 所有与应用程序都由一个前端控制器(FacesServlet)来处理 2. JSF声明周期 FacesServlet充当用户和JSF应用程序之间的…

ztree项目

思路: 创建一个登陆 登陆上去 就是树 每个是的根节点有他所要展示的内容 表 可以有无数个 主要说的是创建树的表 这个是树的一个表 id 是 节点 name 名字 pid 根节点 url 路径 树的页面 后台通过登陆转的页面 转页面 在前台打印出你想要的数据 前台页面 退出 /*…

ztree使用

官方文档地址 http://www.treejs.cn/v3/main.php#_zTreeInfo 各种参数 http://www.treejs.cn/v3/api.php 简单静态调用 <!DOCTYPE html> <html><head><meta charset"utf-8"><title></title><link href"https://cdn…

zTree 简介

zTree 是一个依靠 jQuery 实现的多功能 “树插件”。优异的性能、灵活的配置、多种功能的组合是 zTree 最大优点。 zTree 是开源免费的软件&#xff08;MIT 许可证&#xff09;。如果您对 zTree 感兴趣或者愿意资助 zTree 继续发展下去&#xff0c;可以进行捐助。 zTree v3.0 …

ztree 详解

官网:http://www.treejs.cn/v3/demo.php#_101 里面有例子和demo,齐全。 zTree是一个基于jQuery的树形列表生成控件。 切换语言,点击下载,里面有各种demo: 里面各种demo,比博客写的好。 <!DOCTYPE html> <html lang="en"><head><meta ch…

zTree的简单使用1.0

2018/10/10 北京朝阳.冠城大厦17楼 这里是引用 zTree 简介 zTree 是一个依靠 jQuery 实现的多功能 “树插件”。优异的性能、灵活的配置、多种功能的组合是 zTree 最大优点。 zTree 是开源免费的软件&#xff08;MIT 许可证&#xff09;。如果您对 zTree 感兴趣或者愿意资助 zT…

ZTree基本使用及本人详解

文章目录 ZTree树简介简介ZTree的特点练习ztree之前的小建议ZTree文件介绍ZTree的配置介绍 ZTree使用案例需求1&#xff1a;前端初始化数据&#xff08;标准json数据&#xff09;前端代码 需求2&#xff1a;后端查询ztree数据&#xff08;简单JSON数据&#xff09;需求3&#x…

ztree 使用教程

zTree 是一个依靠 jQuery 实现的多功能 “树插件”。被广泛应用在系统的权限管理中&#xff0c;本文讲解zTree的一般应用 zTree 官网 http://www.treejs.cn/v3/main.php#_zTreeInfo 1、zTree 官网下载 ztree 下载好后放到项目相关目录下 2、编写相关代码 引入相关js 、 css …