类和对象(下)

一.再谈构造函数

  • 构造函数有构造函数体赋值实现和初始化列表两种方式

1.构造函数体赋值

在创建对象时,编译器通过调用构造函数,给对象中各个成员变量一个合适的初始值.
在这里插入图片描述
虽然上述构造函数调用之后,对象中已经有了一个初始值,但是不能将其称为对对象中成员变量的初始化,构造函数体中的语句只能将其称为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。

2.初始化列表

是对象的成员定义的位置
(1)语法结构

以一个冒号开始,接着是一个以逗号分隔的数据成员列表,每个"成员变量"后面跟一个放在括号{}中的初始值或表达式(构造函数体)。

class Myclass
{
public:Myclass(int x, int y):member1(x), member2(y){//构造函数体}private:int member1;int member2;
};

(2)特性
1.初始化列表只能初始化一次,多次会报错

在这里插入图片描述

2.编译器允许构造函数体赋值与初始化列表混用。初始化列表优先,初始化列表中成员变量初始化操作在构造函数体之前完成。

在这里插入图片描述

3.若在初始化列表和构造函数体中对同一个成员变量进行赋值,构造函数体内的赋值会覆盖初始化列表中的值

在这里插入图片描述

4.引用成员变量const成员变量自定义类型成员(且该类没有默认构造函数时)必须放在初始化列表位置进行初始化。

在这里插入图片描述

这三种类型成员若在构造函数体内进行赋值初始化会报错
在这里插入图片描述
在这里插入图片描述

const成员变量、引用成员变量、没有默认构造函数的自定义类型成员变量必须在初始化列表内初始化的原因
1**.初始化列表是对象的成员定义的位置**
2.const成员变量:一旦被赋值就不能被修改,必须在初始化列表中赋值,因为它们不能在构造函数体中被修改。
3.引用成员变量:必须在初始化列表中绑定,因为引用在声明时就必须绑定到一个有效的对象或变量上,不能重新绑定。
4.没有默认构造函数的自定义类型成员变量:必须通过初始化列表显示调用构造函数进行初始化,因为编译器无法自动完成。

5.尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。

具有以下优点:
1.效率提升
避免默认构造:对于自定义类型若不使用初始化列表,默认情况下编译器会先调用默认构造函数创建对象,然后再进行赋值操作,使用初始化列表可以直接进行构造,避免了不必要的默认构造和复制操作。
减少复制操作:对于大型对象或容器,减少复制次数可以显著提高程序的允许效率。
2.必要性
在上述内容中已写明对那三种成员变量只能在初始化列表中进行初始化。
3.代码简洁性
当需要初始化多个成员变量时,使用初始化列表可增加可读性。而构造函数体内可能设计复杂的逻辑判断等条件。

6.成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

在这里插入图片描述
为什么有随机数结果呢?
因为我们认为在初始化列表中先对a1进行初始化,再用a1的值对a2初始化,但实际上初始化的顺序是按照成员变量在类中的声明次序来的。所以先对a2初始化,这时a1未知所以结果是随机值,然后再对a1初始化为1.
所以建议初始化列表中变量声明顺序与在类中的声明顺序保持一致

二.explicit关键字

1.隐式类型转换

(1)内置类型的隐式类型转换

在这里插入图片描述
double e=y;并不是直接将y赋值给e,而是由y创建一份临时变量,再把临时变量的值给e,e改变的是临时变量的值而不是y的值。
在这里插入图片描述
若e采用引用的方式,前面必须加上const修饰,因为e不是y的引用,而是临时变量的引用,临时变量具有常性,若不加const会造成权限放大的问题。
在这里插入图片描述
在这里插入图片描述

(2)自定义类型的隐式类型转换

在这里插入图片描述
在这里插入图片描述

怎么发生隐式类型转换的呢?
先由2构造一个A的临时对象,临时对象再拷贝构造aa2.即先构造,再拷贝构造。但根据结果看出,编译器会进行优化(不允许对同一对象构造两次),会直接调用A aa2(2)构造

与内置类型相同,涉及到含引用的隐式类型转换,必须加const修饰

在这里插入图片描述

2.禁止单参构造函数的隐式类型转换

构造函数不仅可以构造与初始化对象,对于接收单个参数的构造函数,还具有类型转换的作用。接收单个参数的构造函数具体表现:

  1. 构造函数只有一个参数

在这里插入图片描述

  1. 构造函数有多个参数,除第一个参数没有默认值外,其余参数都有默认值

在这里插入图片描述

  1. 全缺省构造函数(比上图多一个缺省值,省略)

来看一个explicit使用场景
在这里插入图片描述
在这里插入图片描述
与自定义类型隐式转换代码相同,用explicit修饰构造函数,将会禁止构造函数的隐式转换

三.static成员

概念:声明为static的类成员称为类的静态成员,用static修饰的成员变量,称之为静态成员变量;用static修饰的成员函数,称之为静态成员函数静态成员变量一定要在类外进行初始化

实现一个类,计算程序中创建出了多少个类对象

class A
{
public:A() { ++_scount; }A(const A& t) { ++_scount; }~A() { --_scount; }static int GetACount() { return _scount; }
private:static int _scount;
};
//全局位置,类外面定义
int A::_scount = 0;
void TestA()
{cout << __LINE__<<":"<<A::GetACount() << endl;A a1, a2;A a3(a1);cout << __LINE__ << ":" << A::GetACount() << endl;
}int main()
{cout <<__LINE__<<":"<< A::GetACount() << endl;  // 1A aa1;TestA();return 0;
}

该类通过记录调用构造函数和拷贝构造函数次数来计算创建了多少个类对象,通过记录调用析构函数来判断销毁了多少个类对象
该类的实现必须使用静态成员变量和静态成员函数原因在于:
成员变量:属于每一个类对象自身,存储在对象里面
静态成员变量:属于类,属于类的每个对象共享,存储在静态区

因为普通成员变量属于每个对象自身,无法在多个对象间共享信息来统计类对象创建总次数,而静态成员变量为类所拥有且被共享,所以能在每个类对象被创建调用默认构造函数时记录对象数量。

特性:

  1. 静态成员为所有类对象所共享,不属于某个具体的对象,存放在静态区。相当于用类去封装全局变量
  2. 静态成员变量必须在类外定义定义时不添加static关键字(定义的目的是为其分配实际的内存空间,而不是再次声明其静态属性),类中只是声明
  3. 类静态成员即可用 类名::静态成员 或者 对象.静态成员 来访问,即突破类域和访问限定符就可以访问
  4. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员,非静态成员可以访问静态成员
  5. 静态成员也是类的成员,受public、protected、private 访问限定符的限制
    6.静态成员不能给缺省值,没有初始化列表,缺省值是给初始化列表的。

四:友元

概念:友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度(模块间的关联程度,越低越独立),破坏了封装,所以友元不宜多用。友元分为:友元函数和友元类

1.友元函数

问题:现在尝试去重载operator<<,然后发现没办法将operator<<重载成成员函数**。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置**。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以要将operator<<重载成全局函数。但又会导致类外没办法访问成员,此时就需要友元来解决。operator>>同理。

class Date
{friend ostream& operator<<(ostream& _cout, const Date& d);friend istream& operator>>(istream& _cin, Date& d);
public:Date(int year = 2025, int month = 1, int day = 19): _year(year), _month(month), _day(day){}
private:int _year;int _month;int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{_cout << d._year << "-" << d._month << "-" << d._day;return _cout;
}
istream& operator>>(istream& _cin, Date& d)
{_cin >> d._year;_cin >> d._month;_cin >> d._day;return _cin;
}
int main()
{Date d;cin >> d;cout << d << endl;return 0;
}

友元函数可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字

特性说明:
1.友元函数可访问类的私有和保护成员,但不是类的成员函数
2.友元函数不能用const修饰(没有this指针)
3.友元函数可以在类定义的任何地方声明,不受类访问限定符限制
4.一个函数可以是多个类的友元函数
5.友元函数的调用与普通函数的调用原理相同

2.友元类

友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。
1.友元关系是单向的,不具有交换性
假如有Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
2.友元关系不能传递
如果B是A的友元,C是B的友元,则不能说明C时A的友元。
3.友元关系不能继承,在继承位置再给大家详细介绍。

五.内部类

概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去访问内部类的成员。外部类对内部类没有任何优越的访问权限

在这里插入图片描述
比如上述一道oj题中,在Solution类中声明Sum类为其内部类,那么可以在Sum类中直接访问Solution类的私有成员变量,但想在Solution类中访问Sum类中私有的成员变量则不行。
注意:内部类就是外部类的天生友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。
特性:

  1. 内部类可以定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象/类名。
  3. sizeof(外部类)=外部类,和内部类没有任何关系。

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

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

相关文章

在资源有限中逆势突围:从抗战智谋到寒门高考的破局智慧

目录 引言 一、历史中的非对称作战&#xff1a;从李牧到八路军的智谋传承 李牧戍边&#xff1a;古代军事博弈中的资源重构 八路军的游击战&#xff1a;现代战争中的智慧延续 二、创业界的逆袭之道&#xff1a;小米与拼多多的资源重构 从MVP到杠杆解 社交裂变与资源错配 …

eLection: 1靶场渗透测试

eLection: 1 来自 <eLection: 1 ~ VulnHub> 1&#xff0c;将两台虚拟机网络连接都改为NAT模式 2&#xff0c;攻击机上做namp局域网扫描发现靶机 nmap -sn 192.168.23.0/24 那么攻击机IP为192.168.23.182&#xff0c;靶场IP192.168.23.196 3&#xff0c;对靶机进行端口服…

RuleOS:区块链开发的“新引擎”,点燃Web3创新之火

RuleOS&#xff1a;区块链开发的“新引擎”&#xff0c;点燃Web3创新之火 在区块链技术的浪潮中&#xff0c;RuleOS宛如一台强劲的“新引擎”&#xff0c;为个人和企业开发去中心化应用&#xff08;DApp&#xff09;注入了前所未有的动力。它以独特的设计理念和强大的功能特性&…

【MySQL篇】MySQL基本查询详解

目录 前言&#xff1a; 1&#xff0c;Create 1.1&#xff0c;单行数据全列插入 1.2&#xff0c;单行数据指定列插入 1.3&#xff0c;多行数据全列插入 1.4&#xff0c;多行数据指定列插入 1.5&#xff0c;插入否则更新 1.6&#xff0c;替换 2&#xff0c;Retrieve …

第十七:go 反射

fmt.printf("%T"&#xff0c;obj) // 打印 reflect 的类型 fmt.Printf("%T", obj) // *reflect.rtype //打印的是一个指针类型 reflect包 在Go语言中反射的相关功能由内置的reflect包提供&#xff0c;任意接口值在反射中都可以理解为由reflect.Type和…

热门的壁纸创作风格呈现多元化发展趋势

下热门的壁纸创作风格呈现多元化发展趋势&#xff0c;以下是几种主流风格及其特点&#xff1a; 简约现代风格 流行元素&#xff1a;以简洁的线条、纯净的色彩块面和少量的抽象图形为主。摒弃过多繁杂的装饰&#xff0c;强调形式追随功能的设计理念。热度分析&#xff1a;在各大…

【SpringMVC】深入解析使用 Postman 在请求中传递对象类型、数组类型、参数类型的参数方法和后端参数重命名、及非必传参数设置的方法

SpringMVC—请求传参 1. 传递对象 如果参数比较多时&#xff0c;方法声明就需要有很多形参&#xff1b;并且后续每次新增一个参数&#xff0c;也需要修改方法声明. 我们不妨把这些参数封装为一个对象&#xff1b; Spring MVC 也可以自动实现对象参数的赋值&#xff0c;比如 Us…

AI智能眼镜的视觉革命:算法如何重塑人机交互新纪元

引言&#xff1a;视觉算法的核心地位与AI智能眼镜的崛起 AI智能眼镜作为下一代交互终端&#xff0c;其核心价值在于将视觉感知与人工智能深度融合&#xff0c;通过实时环境解析与动态反馈&#xff0c;重新定义人机交互的边界。据预测&#xff0c;2025年全球AI智能眼镜销量将突…

掌握 ArcGIS Pro:古地图制作技巧与方法

在探索历史的长河中&#xff0c;古地图以其独特的魅力承载着丰富的地理信息和历史文化价值。 随着技术的进步&#xff0c;现代地理信息系统&#xff08;GIS&#xff09;如ArcGIS Pro为我们提供了强大的工具&#xff0c;使制作古地图成为可能。 本文将详细介绍如何使用ArcGIS …

MySQL的安装及配置

一.以安装包方式下载 1.进入MySQL官网&#xff0c;下载安装包 官网链接&#xff1a;https://downloads.mysql.com/archives/installer/ 2.安装MySQL 二.压缩包方式下载 下载位置&#xff1a;mysql下载位置 解压缩后位置&#xff1a;D:\mysql-8.0.15-winx64 在主目录下复制…

Python实例:PyMuPDF实现PDF翻译,英文翻译为中文,并按段落创建中文PDF

基于PyMuPDF与百度翻译的PDF翻译处理系统开发:中文乱码解决方案与自动化排版实践 一 、功能预览:将英文翻译为中文后创建的PDF 二、完整代码 from reportlab.lib.pagesizes import letter from reportlab.lib.styles import getSampleStyleSheet, ParagraphStyle

『VUE』vue 引入Font Awesome图标库(详细图文注释)

目录 Font Awesome介绍安装引入npm 安装导入src/main.js 使用总结 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 欢迎关注 『VUE』 专栏&#xff0c;持续更新中 Font Awesome介绍 我一般是中文网搜索找到图标的英文名然后去官方网站搜索 官方网站(英文名搜索) https://font…

0基础 | 看懂原理图Datasheet 系列1

原理图功能分类 控制部分&#xff1a;整个电路板的核心控制和计算部分&#xff08;CPU&#xff09; CPU最小系统是什么?电源时钟复位 接口部分&#xff1a;实现特定功能的部分 如Wife模块、通讯接口 电源部分&#xff1a;整个电路板的供电部分 任何电路板都是必要的&…

python-leetcode-删掉一个元素以后全为 1 的最长子数组

1493. 删掉一个元素以后全为 1 的最长子数组 - 力扣(LeetCode) 可以使用滑动窗口的方式来解决这个问题。我们要找到最长的全 1 子数组,但必须删除一个元素,因此可以将问题转化为寻找最多包含一个 0 的最长子数组。 解题思路 使用双指针(滑动窗口),维护窗口内最多包含一…

ubuntu挂载新硬盘

在准备数据的时候出现空间不够的问题&#xff1a; 添加200G的空间&#xff0c;挂在到/home/vipuser/BEV_Depth/BEVDepth/data/nuScenes 使用lsblk查看挂载的盘 有两块硬盘 vda 和 vdb&#xff0c;其中 vda 已经用于系统安装&#xff0c;vdb 尚未分区和挂载。 1. **分区新磁盘…

Java 生成图形验证码

一、图形验证码的意义 图形验证码是一种广泛应用于互联网领域的安全验证机制&#xff0c;它通过向用户展示包含字符、数字、图形等信息的图片&#xff0c;要求用户正确识别并输入其中的内容&#xff0c;以此来区分用户是人类还是机器程序。图形验证码具有多方面重要意义&#…

Qwen/QwQ-32B 基础模型上构建agent实现ppt自动生成

关心Qwen/QwQ-32B 性能测试结果可以参考下 https://zhuanlan.zhihu.com/p/28600079208https://zhuanlan.zhihu.com/p/28600079208 官方宣传上是该模型性能比肩满血版 DeepSeek-R1&#xff08;671B&#xff09;&#xff01; 我们实现一个 使用Qwen/QwQ-32B 自动生成 PowerPoi…

ios 小组件和数据共享

创建主工程就不必讲了 1 创建小组件 创建子工程 [new Target ] 选择 [ Widger Extension] 小组件入口是WidgetBundle文件&#xff0c;可以进行多个小组件的调试 TestWidget2文件是主要操作&#xff0c;小组件使用swiftUI布局&#xff0c;使用 AppIntent进行事件处理&#xff…

C++【类和对象】(超详细!!!)

C【类和对象】 1.运算符重载2.赋值运算符重载3.日期类的实现 1.运算符重载 (1).C规定类类型运算符使用时&#xff0c;必须转换成调用运算符重载。 (2).运算符重载是具有特殊名字的函数&#xff0c;名字等于operator加需要使用的运算符&#xff0c;具有返回类型和参数列表及函数…

ExBody2: Advanced Expressive Humanoid Whole-Body Control

ExBody2: Advanced Expressive Humanoid Whole-Body Control 研究动机解决方案技术路线实验结果 ExBody2: Advanced Expressive Humanoid Whole-Body Control 研究动机 高维状态空间和复杂控制限制了人形机器人在现实世界中的应用。人形机器人和人类在身体结构上有很大不同&a…