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

news2024/9/22 9:42:56

标题:【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;

编译报错


(图片来源于网络)


完~

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

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

相关文章

linux系统(ubuntu)调用科大讯飞SDK实现语音识别

1. 科大讯飞官网 登录注册实名制 2. 点击控制台&#xff0c;创建应用 点击左侧的语音听写&#xff0c;右边下滑选择Linux&#xff0c;点击下载 选择Linux平台&#xff0c;普通版本&#xff0c;语音听写&#xff0c;SDK下载 此时将得到一个压缩包&#xff0c;选择的功能不…

LVS的三种工作模式---(DR/TUN/NAT)

目录 一、NAT模式&#xff08;LVS-NAT&#xff09; 二、IP隧道模式&#xff08;LVS-TUN&#xff09; 三、DR模型--直接路由模式&#xff08;LVS-DR&#xff09; LVS/DR模式ARP抑制 原因&#xff1a; LVS的DR工作模式及配置&#xff1a; LVS的NAT工作模式及配置&#xff1…

邂逅Linux--常见指令,万物为文件(一)

引子&#xff1a;在之前&#xff0c;我们经常听到Linux&#xff0c;那什么是Linux呢&#xff1f;Linux是一种免费使用和自由传播的类UNIX操作系统&#xff0c;其内核由林纳斯本纳第克特托瓦兹&#xff08;Linus Benedict Torvalds&#xff09;于1991年10月5日首次发布&#xff…

命令行工具部署达梦数据库 DMDPC(BP 多副本架构)

解达梦数据库DPC集群的主要使用场景&#xff1a; DMDPC 关注和解决的是大数据、计算与存储分离、高可用、支持全部的 SQL 标准、拥有完整的事务处理能力和集群规模能够动态伸缩的业务场景&#xff1a; 大量的复杂查询操作要求优化器能够生成优良的执行计划&#xff0c;并且执…

0基础理解ECC并做题-攻防世界easy-ECC理解

基点p就是最初选定的那个点 1和2都是整数集合&#xff0c;但是1/20.5就不属于整数集合 一直加&#xff0c;一直乘&#xff0c;还能保证有限个数字&#xff1f;这是因为采用了取模的运算&#xff0c;让元素始终都在有限的范围内。 如何计算分数求模&#xff1f; 设n1/2mod23,那么…

使用注解的方式进行配置RabbitMQ

引入依赖&#xff1a; <dependency><groupId>org.springframework.amqp</groupId><artifactId>spring-rabbit-test</artifactId><scope>test</scope></dependency> 配置application.yml server:port: 8082 spring:rabbitmq…

Coze扣子开发指南:AI零代码编程创建插件

在Coze扣子中创建插件&#xff0c;有两种方式&#xff0c;一是用API&#xff0c;具体方式参照上一篇文章《Coze扣子开发指南&#xff1a;用免费API自己创建插件》&#xff0c;还有一种方式就是编程&#xff0c;不过有了AI的帮助&#xff0c;即使不会编程的人&#xff0c;也可以…

如何清除DNS缓存,刷新DNS

大家在使用域名访问服务器的时候&#xff0c;经常会遇到一个问题&#xff0c;同一个局域网里的两台电脑&#xff0c;一台可以访问而另一台不行。这是为什么呢&#xff1f;这里我要和大家说下DNS缓存的问题&#xff0c;顾名思义&#xff0c;每台电脑都有DNS缓存&#xff0c;在域…

MyBatis-plus(一):快速入门

目录 一、MyBatis-plus 快速入门 1、原理 2、实体类命名规则 3、常见注解 4、主键 id 策略 5、使用 TableField 的常见场景 6、常用配置 二、核心功能 1、条件构造器 2、自定义 SQL 3、IService 接口 一、MyBatis-plus 快速入门 1、原理 MyBatisPlus 通过扫描实体…

Leetcode 剑指 Offer II 077.排序链表

题目难度: 中等 原题链接 今天继续更新 Leetcode 的剑指 Offer&#xff08;专项突击版&#xff09;系列, 大家在公众号 算法精选 里回复 剑指offer2 就能看到该系列当前连载的所有文章了, 记得关注哦~ 题目描述 给定链表的头结点 head &#xff0c;请将其按 升序 排列并返回 排…

STM32入门_江协科技_5~6_OB记录的自学笔记_GPIO输出_LED流水灯_蜂鸣器

5. GPIO 输出 5.1. GPIO简介 GPIO&#xff08;General Purpose Input Output&#xff09;通用输入输出口可配置为8种输入输出模式引脚电平&#xff1a;0V~3.3V&#xff0c;部分引脚可容忍5V&#xff08;端口输入5V的电压&#xff0c;之前引脚定义表格中带FT标识的&#xff09…

暗区突围哪里获得测试资格 暗区突围测试资格获取方法

在游戏业界的浩瀚星空中&#xff0c;《暗区突围》如同一颗璀璨新星&#xff0c;以其独树一帜的游戏模式和前所未有的沉浸式体验&#xff0c;迅速吸引了全球玩家的目光。它不仅仅是一款游戏&#xff0c;更像是一次对勇气、智慧与团队合作的深度探索。玩家在危机四伏的暗区中&…

【软考高项】四十四、高级项目管理

一、项目集管理 相关角色 项目集发起人、项目集指导委员会、项目集经理、其他影响项目集的干系人项目集管理绩效域 项目集战略一致性、项目集效益管理、项目集干系人参与、项目集治理和项目集生命周期管理 二、项目组合管理 项目组合经理角色 项目组合管理原…

软件测试报告(交付文档支撑word原件)

软件测试报告在软件开发过程中起着至关重要的作用&#xff0c;主要有以下几个主要原因&#xff1a; 1、确保软件质量 2、提供决策支持 3、记录测试过程和结果 4、促进沟通和协作 5、符合标准和法规要求 6、改进测试流程和策略 7、降低风险 软件开发全套资料获取进主页或者本文…

【字符函数与字符串函数】

文章目录 一、strlen函数1.strlen函数的使用2.strlen函数的模拟实现(1)计算器办法(2)不创建临时变量计数器(3)指针 二、strcpy函数1、strcpy函数的使用2、strcpy函数的模拟实现 三、strcat函数1、strcat函数的使用2、strcat模拟实现3、字符串自己给自己追加&#xff1f; 四、st…

2024年数维杯数学建模

高质量原创论文已完成 需要的私我

构建内网yum仓库

1、环境介绍 系统&#xff1a;龙蜥os 7.9 2、安装epel源 yum install epel-release -y3、安装nginx服务器并启动 yum install nginx httpd -y配置 server {listen 80;server_name repo.wtown.com;root /usr/share/nginx/html/repo;index index.html index.htm;location / {…

信息安全-古典密码学简介

目录 C. D. Shannon: 一、置换密码 二、单表代替密码 ① 加法密码 ② 乘法密码 ③密钥词组代替密码 三、多表代替密码 代数密码 四、古典密码的穷举分析 1、单表代替密码分析 五、古典密码的统计分析 1、密钥词组单表代替密码的统计分析 2、英语的统计规…

报表-集成

1、部署报表服务器 以centos为例 1.1 将服务拷贝到服务器 其中JDK-17是对应平台的jdk 1.2 修改lite-report下的source.config 1.3 把设计好的报表文件拷贝到lite-report/report 1.4 启动服务&#xff1a;sh run.sh restart 2、使用Nginx location /litereport/ { …

前端笔记-day1

文章目录 01-标签的写法02-HTML的基本骨架03-标签的关系04-注释05-标题标签06-段落标签07-换行与水平线标签08-文本格式化标签09-图像的基本使用10-图像的属性12-绝对路径13-超链接14-音频15-视频标签16-招聘案例18-个人简历19-vue简介 01-标签的写法 <strong>文字内容&…