【C -> Cpp】由C迈向Cpp (5)

标题:【C -> Cpp】由C迈向Cpp(5)

@水墨不写bug


(图片来源于网络)


不抵制失败,携手失败,迈向成功


正文开始:

(一)深入理解构造函数

        在之前的讲解中,我们已经对 不写会默认生成的 常用的 成员函数有了一个基本的认识,对于一个类而言,用一句话概括常用的成员函数的功能:

        构造函数:完成对象的实例化(定义)。

        析构函数:完成对象销毁前资源清理。

        拷贝构造:在创建对象的同时完成赋值。

        赋值重载:将一个对象赋值给另一个对象。


        尽管我们已经对这些成员函数们有一个整体的认识了。然而,我们需要抓一抓构造函数的细节,以便于对它有一个更深的认识:


        构造函数分为两部分-->  初始化列表和函数体


(1)初始化列表 

使用方式:

        跟在构造函数的函数头后,在函数体之前

        每一个成员变量都用 “  变量名()”初始化;

        第一个成员变量之前为 “  ”,成员变量之间用  “ ”分隔。


示例:

#include <iostream>
using namespace std;
class Date
{
public:
    //构造函数
    Date(int year = 0, int month = 0, int day = 0)
        :_year (year)
        ,_month (month)
        ,_day  (day)
    {}
    
private:
    int _year;
    int _month;
    int _day;
};

        构造函数有一个举足轻重的功能:初始化列表。

        一般情况下,几乎所有 成员变量 都可以在初始化列表 初始化。

(成员变量不论是内置类型,还是自定义类型)

        初始化列表是成员变量初始化的唯一方式。因为从本质上,在构造函数函数体内部对成员变量的赋值之后还可以多次改变,所以构造函数内对成员变量赋值不是初始化,而是赋初值。

不同对象的初始化方式:

        1.引用成员变量、const成员变量、自定义类型的成员变量(这个自定义类型没有默认构造)这三类 必须在初始化列表初始化。

        2.自定义类型对象和内置类型对象的初始化

        ###初始化列表无论你写不写它总是存在的。当然,写初始化列表,并一个不漏的初始化是最好的情形。但是如果不写,可能就会发生一些意想不到的问题###


        不写初始化列表——>

  •         内置对象 在Cpp 语法上没有明确规定,取决于编译器的不同。有些编译器会对内置类型处理,不过大多数编译器不会对内置对象处理。
  •         自定义对象 会调用其默认构造函数,如果调用默认构造函数失败,报出错误。

什么是调用默认构造函数失败?

/************************************/

        要理解这个问题,我们先看看什么是默认构造

  •  i, 自己没有写,编译器自动生成的的构造函数是无参数的构造函数,也就是默认构造;
  • ii,自己写了一个函数,但是没有参数,也可以被编译器识别为默认构造函数,这时编译器就不会再自动生成一个构造函数了;
  • iii,自己写了一个函数,有参数,但是参数全缺省,这也可被编译器识别为默认构造函数,这时编译器就不会再自动生成一个构造函数了;

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。


原文链接:https://blog.csdn.net/2301_79465388/article/details/138410081

/***********************************/

       

        也就是说明:

        如果没有默认构造,并且编译器也无法生成时,就会调用默认构造函数失败。

        3.成员变量的缺省值是对初始化列表的补充。

        

        由于不写初始化列表——>大多数编译器不会对内置对象处理。所以C++11新增成员变量的缺省值,缺省值的给出是 非常灵活的,请看如下示例中的 P类

示例: 

        


#include<iostream>
#include<cstdlib>
using namespace std;
class Stack
{
public:

	Stack()
	{
		int* tem = (int*)realloc(_arr, sizeof(int) * n);
        if (tem == nullptr)
        {
	        perror("realloc fail");
	        exit(-1);
        }
        _arr = tem;

    }
private:
	int _top = 0;
	int* arr = (int*)malloc(sizeof(int)*4);
};


class P
{
public:

	P()
	{}

	double re_Pi()
	{
		return 3.1415926;
	}
private:

/*成员默认值给出是非常灵活的*/

    //可以是常量值
	int _a = 0;
	char _c = 'c';

    //常量表达式
	long _b = 8 + 3;

    //函数返回值
	double pi = re_Pi();

    //动态申请的空间指针
    int* ptr = (int*)malloc(sizeof(int)*4);

    //另一个对象并调用构造
	Stack st = 10;
};

通过单步调试,我们可以观察的很清楚 :

1.首先进入P的构造函数,准备进入初始化列表(没有写也是存在的)

 

2.进入初始化列表,用默认值初始化成员变量。

 默认值为函数返回值也是可以正常进入的:

 对于栈的初始化也是可以正常找到默认构造的:

初始化完成:


        4,成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关。
示例:


/*这个程序的输出结果是什么*/


class A
{
public:
    A(int a)
    :_a1(a)
    ,_a2(_a1)
    {}

    void Print() 
    {
    cout<<_a1<<" "<<_a2<<endl;
    }

private:
    int _a2;
    int _a1;
};

int main() 
{
    A aa(1);
    aa.Print();
}

        其实结果是输出:     {   1     随机值    }

(因为初始化列表是根据成员变量声明顺序来初始化的,由于先声明_a2,所以先初始化_a2,这时_a1还是随机值,所以_a2初始化是被随机值初始化的,是无效的)

 构造函数的初始化列表总结:

        &能在初始化列表的尽量都在初始化列表初始化,如果实在不能再考虑在构造函数的函数体内进行赋值&

(2)explicit关键字

用explicit修饰构造函数,将会禁止构造函数的隐式转换

        构造函数 其实做了比我们想象的更多的事:

class Date
{
public:

    // 1. 单参构造函数,没有使用explicit修饰,具有类型转换作用
    
    explicit Date(int year)
        :_year(year)
        {}

   

    Date& operator=(const Date& d)
    {
        if (this != &d)
        {
            _year = d._year;
            _month = d._month;
            _day = d._day;
        }
        return *this;
    }
private:
    int _year;
    int _month;
    int _day;
};

 对于这个类,当我们构造对象

int main()
{
    Date d1(2024);
    d1 = 2023;
    return 0;
}

        2023赋值给d1,构造函数则完成了将整形值隐式类型转换成Date类的临时对象,然后通过赋值重载将临时对象的值赋值给d1。


1.对于任意的单参数的构造函数,当我们传入的类型和对象类型不一致时,都会发生这一转换。

什么是单参数

  • 1. 构造函数只有一个参数
  • 2. 构造函数有多个参数,除第一个参数没有默认值外,其余参数都有默认值
  • 3. 全缺省构造函数

 这也是构造函数让我们用的很方便的原因。

2.如果在构造函数之前加上explicit,就禁止了隐式类型转换。

这样,编译会报错:

加上 explicit之后无法完成类型转换:

d1 = 2023;

编译报错


(图片来源于网络)


完~

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

安装Ununtu后常见问题(无法远程连接、root密码等)

安装Ununtu后常见问题&#xff08;无法远程连接、root密码、无法ifconfig等&#xff09; 提示&#xff1a;安装完Ununtu系统后会遇到一些常见的问题&#xff0c;本文一次洗解决 文章目录 安装Ununtu后常见问题&#xff08;无法远程连接、root密码、无法ifconfig等&#xff09;一…

Linux(Ubuntu24.04) 安装 MinIO

本文所使用的 Ubuntu 系统版本是 Ubuntu 24.04 ! # 1、下载 MinIO wget https://dl.min.io/server/minio/release/linux-amd64/minio# 2、添加可执行权限 chmod x minio# 3、导出环境变量&#xff0c;用于设置账号密码&#xff0c;我设置的账号和密码都是 minioadmin export MI…

PyQt5中的QtDesigner窗口

文章目录 1. 简介2. QtDesigner的MainWindow2.1 创建MainWindow2.2 添加组件2.3 预览2.4 查看对应的Python代码2.5 保存窗口并命名为login.ui&#xff0c;如下所示2.6对ui文件进行转换得到.py原件 3. 窗口常用属性及说明3.1 设置对象名称3.2 改变标题名字3.3 修改窗口大小 4. 更…

PyCharm 集成 Git

目录 1、配置 Git 忽略文件 2、定位Git 3、使用pycharm本地提交 3.1、初始化本地库 3.2、添加到暂存区 3.3、提交到本地库 3.4、切换版本 4、分支操作 4.1、创建分支 4.2、切换分支 4.3、合并分支 5、解决冲突 1、配置 Git 忽略文件 作用&#xff1a;与项目的实际…

conan2 基础入门(04)-指定编译器(gcc为例)

conan2 基础入门(04)-指定编译器(gcc为例) 文章目录 conan2 基础入门(04)-指定编译器(gcc为例)⭐准备生成profile文件预备文件和Code ⭐使用指令预览正确执行结果可能出现的问题 ⭐具体讲解conancmake ENDsettings.yml ⭐准备 生成profile文件 # 生成默认profile文件&#xf…

【userfaultfd+条件竞争劫持modprobe_path】TSGCTF 2021 -- lkgit

前言 入门题&#xff0c;单纯就是完成每日一道 kernel pwn 的 kpi &#x1f600; 题目分析 内核版本&#xff1a;v5.10.25&#xff0c;可以使用 userfaultfd&#xff0c;不存在 cg 隔离开启了 smap/smep/kaslr/kpti 保护开启了 SLAB_HADNERN/RANDOM 保护 题目给了源码&…

使用IDA自带python patch的一道例题

首先看见就是迷宫 迷宫解出的路径&#xff0c;放在zip的文件可以得到一个硬编码 然后在原程序中&#xff0c;有一处很离谱 这个debugbreak就是IDA分析错误导致的 我们点进去发现里面全是nop 然后我们把我们得到的硬编码放在010里面&#xff0c;再用IDA打开 重新编译看汇编 你…

Python---Numpy万字总结(2)

NumPy的应用&#xff08;2&#xff09; 数组对象的方法 获取描述统计信息 描述统计信息主要包括数据的集中趋势、离散程度和频数分析等&#xff0c;其中集中趋势主要看均值和中位数&#xff0c;离散程度可以看极值、方差、标准差等 array1 np.random.randint(1, 100, 10) …

音视频--AAC编码解析和示例

目录 1&#xff1a;AAC编码介绍 2&#xff1a;AAC格式介绍 3&#xff1a;AAC -ADTS帧组成 4&#xff1a;AAC-ADTS&#xff1a;&#xff08;adts_fixed_header&#xff09;格式介绍 5&#xff1a;AAC-ADTS&#xff1a;&#xff08;adts_variable_header&#xff09;格式介绍…

符合Misra C++标准且支持mmap的内存池管理模块

概述 定义内存管理的相关行为。使用了预分配的管理&#xff0c;先分配一块足够大的内存&#xff0c;然后需要时再从这块内存中进行分配。 代码仓库&#xff1a;https://gitee.com/liudegui/mem_pool 类之间的关系 模块名功能MemPool内存池模块入口&#xff0c;提供常用的模块…

HDFS- DataNode磁盘扩缩容

HDFS- DataNode磁盘扩缩容 背景: 缩减/增加节点磁盘 方案介绍: 采用hdfs dfsadmin -reconfig 动态刷新配置实现,不停服扩缩容。 注意事项: 请在进行缩容之前,务必了解实际的数据量,并确保磁盘有足够的空间来容纳这些数据。还需要考虑未来的使用需求,要预留一定数量的空间…

面向电商家居行业3D室内场景合成中的空间感知

本文主要介绍了3D场景合成技术在电商领域&#xff0c;尤其是家居家装行业的应用。它解释了如何使用3D场景合成创建逼真的室内设计&#xff0c;让消费者能够交互式地查看和体验产品&#xff0c;提高购物的趣味性和效率。文章提到了两种主要的3D室内场景生成算法&#xff1a;传统…

Curator分布式锁

系列文章目录 文章目录 系列文章目录前言 前言 前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到网站&#xff0c;这篇文章男女通用&#xff0c;看懂了就去分享给你的码吧。 分布式锁服务宕机,…

RZ9692实训开发通信系统构建(含配置json配置文件)

实验名称 通信系统的构建 实验目的&#xff1a; 实现一个通信系统的构建&#xff0c;要求传输两路正弦波&#xff0c;和一路视频信号&#xff0c;要求在接受端完整接受正弦信号和视频信号。 一、实验原理&#xff1a; 数字通信系统的一般模型&#xff1a; 数字通信系统的一…

验证搜索二叉树

目录 题目 方法一 思路 优化 方法二 思维误区 递归关系推导 代码实现 题目 98. 验证二叉搜索树 难度&#xff1a;中等 给你一个二叉树的根节点root &#xff0c;判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&#xff1a; 节点的左子树只包含…

Python 开发 框架安全:Django SQL注入漏洞测试.(CVE-2021-35042)

什么是 Django 框架 Django 是一个用 Python 编写的 Web 应用程序框架。它提供了许多工具和库&#xff0c;使得开发 Web 应用程序变得更加容易和高效。Django 遵循了“MTV”&#xff08;模型-模板-视图&#xff09;的设计模式&#xff0c;将应用程序的不同组件分离开来&#x…

QT的C++版本是如何从ui文件编译成C++可以使用的.h文件的

Desktop_Qt_6_7_0_MinGW_64_bit是一个编译器&#xff0c;可以将ui文件编译为.h文件。我们可以在项目文件下看到这一样一个文件&#xff1a; 这里的ui_mainwindow.h文件我们可以打开看一下&#xff1a;你会发现你所有的ui设计都被记录在了这里。 /***************************…

最新网页版USB转串口芯片CH340中文规格书手册(20240511)

前言 南京沁恒的产品已经很成熟了&#xff0c;完全可替代国外USB转串口产品&#xff0c;不必迷信FT232&#xff0c;CP2102之类了。 另外&#xff0c;急着买芯片&#xff0c;直接跑过去的&#xff0c;看过几次妹子了:) CH340手册&#xff0c;基于网页3.3版本&#xff0c;规格书…

作为一名新能源汽车热管理仿真工程师需要具备哪些素养与技能

作为一名新能源汽车热管理仿真工程师&#xff0c;需要具备多方面的素养与技能&#xff0c;才能胜任这一岗位的工作。从工程素养到技术技能&#xff0c;再到沟通能力和团队合作&#xff0c;以下是对这些方面的探讨。 理论知识基础 首先&#xff0c;工程素养是新能源汽车热管理仿…

现代制造之数控机床篇

现代制造 有现代技术支撑的制造业&#xff0c;即无论是制造还是服务行业&#xff0c;添了现代两个字不过是因为有了现代科学技术的支撑&#xff0c;如发达的通信方式&#xff0c;不断发展的互联网&#xff0c;信息化程度加强了&#xff0c;因此可以为这两个行业增加了不少优势…