类和对象(下)(1)

server/2024/9/20 3:52:43/ 标签: c++, c语言, 开发语言

类和对象(下)

在这里插入图片描述

再探构造函数

  • 我们之前在实现构造函数的时候,初始化成员变量使用的方式都是在函数体内进行赋值,其实构造函数初始化成员变量还有一种方式:初始化列表

初始化列表不只是为了写得方便,还能解决很多的问题

初始化列表的使用方式

Date(int& x,int year=1,int month=1,int day=1):_year(year),_month(month),_day(day),_t_(12),_ref(x),_n(1)

以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个“成员变量”后面跟一个放在括号中的初始值或表达式。

  • 每个成员变量在初始化列表中只能出现一次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地方。(对象整体定义的时候会去调用构造函数,认为初始化列表就是每个成员变量定义的地方)

  • 我们知道const类型的变量只有一次初始化的机会,这样的写法是不行的:

    const int x;
    x=1;
    

    必须在定义的时候初始化且以后无法改变它。

    所以const修饰的变量必须在初始化列表初始化而不能在函数体内初始化(普通的变量可以在初始化列表初始化也可以在函数体内初始化)。

  • 除了const修饰变量必须在定义的时候(也就是在初始化列表)初始化,还有引用也是一样。因为我们知道引用也必须在定义的地方初始化,下面这样写是不行的:

    int& rx;
    

    上面几点的汇总:

    #include<iostream>
    using namespace std;class Date
    {
    public:Date(int& xx,int year, int month, int day):_year(year)//括号里可以是表达式, _month(month), _day(day),_n(1),_ref(xx){}void Print() const{cout << _year << "-" << _month << "-" << _day << endl;}private://声明int _year;int _month;int _day;//必须在初始列表(定义的地方)初始化const int _n;int& _ref;
    };int main()
    {int x = 0;//对象整体的定义——对象整体定义的时候会去调用构造函数,认为初始化列表就是每个成员变量定义的地方Date d1(x,2024, 8, 18);d1.Print();return 0;
    }
    
    • 还有一类成员变量:没有默认构造的类类型变量,也必须放在初始化列表位置进⾏初始化,否则会编译报错。
class Time
{
public:Time(int hour = 0):_hour(hour){cout << "Time()" << endl;}
private:int _hour;
};class Date
{
public:Date(int& xx,int year, int month, int day):_year(year), _month(month), _day(day),_n(1),_ref(xx){}void Print() const{cout << _year << "-" << _month << "-" << _day << endl;}private://声明 int _year;int _month;int _day;//必须在初始列表(定义的地方)初始化const int _n;int& _ref;Time _t;
};

我们在Date中多加入了一个自定义类型成员变量_t,就算我们不写它的初始化,也会走初始化列表,去调用它的默认构造

如果没有默认构造,我们就要这么写:

	Date(int& xx,int year, int month, int day):_year(year), _month(month), _day(day),_n(1),_ref(xx),_t(1)//就像构造一样去写{}

总结:引⽤成员变量,const成员变量,没有默认构造的类类型变量,必须放在初始化列表位置进⾏初始化,否则会编译报错

初始化列表和函数体内初始化的方式是可以混起来用的,其实有的情况还不得不混起来用,比如成员变量中有指针的情况:

Date(int& xx,int year, int month, int day):_year(year)//括号里可以是表达式, _month(month), _day(day),_n(1),_ref(xx),_t(1)//就像构造一样去写,_ptr((int*)malloc(12))
{if (_ptr == nullptr){perror("malloc fail!");}else{memset(_ptr, 0, 12);}
}
  • 尽量使⽤初始化列表初始化,因为那些你不在初始化列表初始化的成员也会走初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会用这个缺省值初始化。如果你没有给缺省值,对于没有显⽰在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有显示在初始化列表初始化的自定义类型成员会调用这个成员类型的默认构造函数,如果没有默认构造会编译错误。
class Date
{
public:Date(int year, int month, int day):_year(year)//括号里可以是表达式, _month(month)//这里_day的初始化我们不写,也会走初始化列表{}void Print() const{cout << _year << "-" << _month << "-" << _day << endl;}private://声明 int _year;int _month;int _day;};int main()
{int x = 0;Date d1(2024, 8, 18);d1.Print();return 0;
}

初始化列表是每个成员初始化定义的地方。有些变量也可以定义的时候不初始化,这不违反语法规则。所以_day的值我们说是“不确定的”,取决于编译器。

缺省值

C++11还有一种这样的写法:

private://声明 int _year = 1;int _month = 1;int _day = 1;

但它还是声明,不是定义。定义的特点是开空间。这后面的是缺省值。

这个缺省值是给初始化列表用的。如果初始化列表写了就用初始化列表的,如果没写就用缺省值(也可以叫默认值)。

class Date
{
public:Date(int year, int month, int day):_year(year)//括号里可以是表达式, _month(month){}void Print() const{cout << _year << "-" << _month << "-" << _day << endl;}private://声明 int _year = 1;int _month = 1;int _day = 1;};int main()
{Date d1(2024,7,8);d1.Print();return 0;
}

不只是在我们自己写的构造函数中可以用到缺省值,在编译器自动生成的无参的构造函数中也会用到缺省值。以前我们编译器自动生成的构造函数对内置类型不做处理,对自定义类型取调用它的构造,而现在有了缺省值,即使自动生成的,也可以用缺省值来初始化了:

总结:

每个构造函数都有初始化列表,每个成员都要走初始化列表

  1. 在初始化列表初始化的成员

  2. 没有在初始化列表初始化的成员

    a. 声明的地方有缺省值用缺省值

    b.没有缺省值

    ​ x:内置类型,不确定是否初始化,看编译器,大概率随机值

    ​ y:自定义类型,调用默认构造,没有默认构造就编译报错

  3. 引用、const、没有默认构造的自定义类型,这三种必须在初始化列表初始化

所以我们也可以看出来,尽量写初始化列表。

还有一个问题,形参的初始值和声明处写的缺省值是什么关系?不要混为一谈。

  • 初始化列表中按照成员变量在类中声明顺序进行初始化,跟成员在初始化列表出现的的先后顺序无关。建议声明顺序和初始化列表顺序保持⼀致。

    例子:

#include<iostream>
using namespace std;class A
{public:A(int a):_a1(a), _a2(_a1){}void Print() {cout << _a1 << " " << _a2 << endl;}private:int _a2 = 2;int _a1 = 2;
};int main()
{A aa(1);aa.Print();
}

答案为D

为什么初始化列表中按照成员变量在类中声明顺序进行初始化?这是因为声明的顺序其实就是它在内存中存放的顺序。

这些特性确实很复杂,我们可以多实践感受一下。

本文到此结束,类和对象(下)并未讲完,敬请期待后文=_=


http://www.ppmy.cn/server/102066.html

相关文章

【Kubernetes】k8s集群图形化管理工具之rancher

目录 一.Rancher概述 1.Rancher简介 2.Rancher与k8s的关系及区别 3.Rancher具有的优势 二.Rancher的安装部署 1.实验准备 2.安装 rancher 3.rancher的浏览器使用 一.Rancher概述 1.Rancher简介 Rancher 是一个开源的企业级多集群 Kubernetes 管理平台&#xff0c;实…

Nginx与Tomcat的区别

Nginx与Tomcat的区别 —— 经验笔记 引言 在现代Web开发中&#xff0c;选择合适的服务器软件对于构建高性能、可靠的应用程序至关重要。Nginx 和 Tomcat 是两种常见的服务器软件&#xff0c;尽管它们都可以被归类为Web服务器&#xff0c;但它们的设计目标和应用场景有着本质的…

WordPress网站速度优化

提升网站速度对用户体验和搜索引擎排名至关重要。无论你是新手博主&#xff0c;还是经验丰富的网站开发人员&#xff0c;要想优化WordPress网站&#xff0c;需要长时间的努力和坚持。以下是按入门、中级和专家级别介绍的12个实用方法&#xff0c;帮助你提升WordPress网站的整体…

zigbee笔记:十、ZStack(2.3.0-1.4.0)的OSAL使用分析

zigbee笔记&#xff1a;九中&#xff0c;我们已经学会了利用模板&#xff0c;定制自己的个性开发工程&#xff0c;本文为协议栈&#xff08;ZStack-CC2530-2.3.0-1.4.0&#xff09;代码使用分析笔记&#xff0c;来进一步掌握协议栈的使用。 一、协议栈使用知识点 1、协调器、路…

fetch跨域请求数据的前端设置和后端php的header设置

跨源请求&#xff0c;也称为CORS&#xff08;Cross-Origin Resource Sharing&#xff09;请求&#xff0c;是Web开发中常见的一种需求&#xff0c;允许一个网页的JavaScript代码向与该网页不同源的服务器发出HTTP请求。以下是使用JavaScript中的fetch函数进行跨源请求的一个基本…

【51单片机】让AI识别电路图,帮你进行编码(以51单片机为例)

让AI识别电路图,帮你进行编码&#xff08;以51单片机为例&#xff09; ​ 这里使用的AI大模型使用的是 Copilot。&#xff08;两个前提&#xff1a;1. 科学上网、2. 有微软账号&#xff09; 今天测试了一下Copilot识别图片的能力&#xff0c;能力还是可圈可点的。 首先准备一…

C语言日常练习 Day17

目录 一、找出一个二维数组的鞍点 二、有一篇文章&#xff0c;共有3行文字&#xff0c;每行有80个字符。要求分别统计出其中的英文大写字母、小写字母、数字、空格以及其他字符的个数 三、有一行电文&#xff0c;已按下面规律编译成密码&#xff1a;A->Z,a->z,B->Y,…

wordpress视频模板

视频背景wordpress官网主题 红色风格的wordpress主题&#xff0c;首页视频背景&#xff0c;鼠标滚动翻转展示内容&#xff0c;适合公司官网使用。 https://www.jianzhanpress.com/?p7288 MCN传媒wordpress主题 红色风格wordpress大视频背景主题&#xff0c;适合做直播业务的…

【Harmony OS 4.0】水果排行榜案例

ets/example2/Models export class FruitsData {id: stringname: stringvote: stringconstructor(id: string, name: string, vote: string) {this.id idthis.name namethis.vote vote} }ets/example2/TitleComponent // app标题子组件 import APPContext from ohos.app.a…

【ARM 芯片 安全与攻击 5.4 -- Meltdown 攻击与防御介绍】

文章目录 什么是 Meltdown 攻击?Meltdown 攻击的基本原理Meltdown 攻击代码示例Meltdown 攻击在芯片中的应用应用场景Meltdown 攻击与瞬态攻击、测信道攻击的关系针对 Meltdown 攻击的防御硬件级防御Summary什么是 Meltdown 攻击? Meltdown 攻击是一种利用处理器乱序执行(o…

【网络编程】组播的实现(C语言,linux,Ubuntu)

组播 1> 组播也是实现一对多的通信方式&#xff0c;对于广播而言&#xff0c;网络需要对每个消息进行复制转发&#xff0c;会占用大量的带宽&#xff0c;导致网络拥塞 2> 组播可以实现小范围的数据传播&#xff1a;将需要接收数据的接收端加入多播组&#xff0c;发送端…

Linux---05---用户组权限

课程回顾 vim编辑器 本章重点 文件权限 用户管理 用户组管理 一、文件权限 由于Linux是一个多人多任务的系统&#xff0c;因此经常会出现同一台机器同时有多个人进行操作&#xff0c;为了考虑每个人的隐私权以及每个人喜好的工作环境&#xff0c;所以文件的权限归属就至关…

50Kg大载重六旋翼无人机技术详解

50Kg大载重六旋翼无人机的机体结构设计是确保其高承载能力和飞行稳定性的基础。该机体通常采用轻质高强度的材料如碳纤维、铝合金或复合材料构建&#xff0c;以在保证结构强度的同时减轻整机重量。设计过程中&#xff0c;需考虑空气动力学原理&#xff0c;优化机臂布局、机身形…

Leetcode面试经典150题-189.轮转数组

解法都在代码里&#xff0c;不懂就留言或者私信 class Solution {public void rotate(int[] nums, int k) {/**向右轮转 1 步: [7,1,2,3,4,5,6]向右轮转 2 步: [6,7,1,2,3,4,5]向右轮转 3 步: [5,6,7,1,2,3,4]....向右轮转 7 步: [1,2,3,4,5,6,7] *//**既然反转数组的倍数是不需…

oracle使用sql生成表结构文档

oracle使用sql生成表结构文档 背景 客户要求数据资产盘点,需要提供相关表字段的说明文档&#xff0c;指定具体格式。手动是不可能手动的&#xff0c; 使用SQL实现。 要求 实现 生成脚本sql 查询所有非临时表 SELECT table_name FROM all_tables WHERE temporary N;--默认…

sp-eric靶机

端口扫描 靶机ip地址为192.168.7.46 目录扫描 访问80端口 拼接访问 /admin.php 发现登录框 测试sql注入&#xff0c;弱口令等&#xff0c;无结果 扫描目录发现了.git文件&#xff0c;存在源码泄漏 将其下载到kali上读取 python2 GitHack.py -u http://192.168.7.180/.git/…

深入探索CANoe的CAPL语言

概述 在汽车电子和嵌入式系统开发领域&#xff0c;仿真和测试是确保功能正确性和性能标准的关键步骤。Vector公司的CANoe软件是这一领域的佼佼者&#xff0c;它提供了一个强大的平台&#xff0c;用于模拟、测试和分析汽车网络&#xff0c;特别是CAN网络。今天&#xff0c;我们…

无人机电池详解!!!

娱乐型和玩具型无人机 这类无人机的电池容量通常较小&#xff0c;以满足短时间娱乐飞行的需求。电池容量范围一般在500mAh至3000mAh之间&#xff0c;轻便、易携带&#xff0c;适合初学者和休闲玩家。 航拍无人机 普通航拍无人机追求高续航能力&#xff0c;电池容量一般在500…

玩转单例模式

目录 1. 饿汉式 2. 懒汉式 3. volatile解决指令重排序 4. 反射破坏单例模式 5. 枚举创建单例模式 所谓单例模式&#xff0c;就是是某个类的实例对象只能被创建一次&#xff0c;单例模式两种实现&#xff1a;饿汉式和懒汉式。 1. 饿汉式 所谓饿汉式&#xff0c;顾名思义…

Lambda表达式与流式编程

一、Lambda表达式 1.1 什么是lambda表达式 Lambda表达式是 jdk1.8 引入的一个新特性&#xff0c;它是函数式编程在Java中的一种体现。也是1.8最值得学习的新特性。 1. Lambda表达式实际上就是匿名内部类的简化版本。 2. Lambda表达式是jdk1.8引入的一个最重要的新特性&…