【C++】类与对象(3)

news2024/11/28 4:31:25

【C++】类与对象(3)

作者:爱写代码的刚子
时间:2023.5.9
本篇博客干货比较多,主要是对类和对象知识的进一步加深,可能有点晦涩。主要介绍的内容为:深入构造函数,初始化列表,友元,static成员,内部类,对封装的进一步理解。

目录

  • 【C++】类与对象(3)
      • 构造函数理解
          • 初始化列表(是构造函数的一部分)
      • explicit关键字
      • static成员
          • 成员变量和静态成员变量区别
          • 成员函数和静态成员函数区别
          • C++11 的成员初始化新玩法。
      • 友元
          • 友元函数
          • 友元类
          • 内部类(Java常用)
          • 匿名对象
            • const延长匿名对象的生命周期
          • 理解封装

构造函数理解

构造函数不能称作为类对象成员的初始化,构造函数体中的语句只能将其称作为赋初值,而不能称作初始化。因为初始化只能初始化一次,而构造函数体内可以多次赋值。
于是如何对类成员进行初始化?
于是引入初始化列表

初始化列表(是构造函数的一部分)

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

class Date
{
public:
	Date(int year,int month,int day)
		:_year(year)
		,_month(month)
		,_day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};
  • 问题1:既然有构造函数为什么要设计初始化列表?
    有些成员变量必须在初始化列表初始化:
  1. A _aobj;(没有默认构造函数的类)
  2. int& _ref;(引用类型)
  3. const int _n;(const修饰的类型)
    解释:
    以上三种类型都必须在定义的时候初始化,而构造函数的本质并不是初始化而是赋值(函数体内赋值),而初始化列表的执行在构造函数之前,是真正意义上的初始化,所以初始化列表是对象成员定义的位置。
  • 问题2:对成员变量给缺省值和初始化列表冲突吗?
    例:
class Date
{
public:
	Date(int year,int month,int day)
		:x(2)
	{}
private:
	int x=1;
};

解释:
如果在初始化列表中显示地给了x的值,缺省值就失效了,用初始化列表来对x初始化,如果初始化列表中没有对x进行初始化,就会使用缺省值。

  • 问题3如何理解没有默认构造函数的类只能用初始化列表初始化呢?
    例:
class A
{
public:
	A(int a)
	{
		_a = a;
	}
private:
	int _a;
};
class B
{
public:
	B(int b)
		:_b(b)
		, a(2)
	{}
private:
	int _b;
	A a;
};

解释:
这里说的没有默认构造函数(无参构造函数、全缺省构造函数、我们没写编译器默认生成的构造函数)不是指编译器自动生成的默认构造函数,而是指无参构造函数、全缺省构造函数。这里A类写了构造函数所以编译器不会生成无参的构造函数,如果A没有初始化列表,初始化时没有参数传递,加上没有对应的构造函数(无参或全缺省),编译器会报错。

  • 运用:用初始化列表初始化栈:
    注:由于是举例说明,并没有具体实现Stack类。
class MyQueue
{
public:
	MyQueue()
	{}

	MyQueue(int capacity)
		:_pushst(capacity)
		,_popst(capacity)
	{}
private:
	Stack _pushst;
	Stack _popst;
};
  • 注意1:注意引用的初始化!
    举例:
class A
{
public:
	A(int a,int& ref)//注意ref类型,不能为int类型
		:_ref(ref)
		,_n(1)
	{}
private:
	int& _ref;
	int _n;
};

1. 初始化列表中ref必须是引用类型,如果是局部变量会导致ref销毁,_ref初始化后变为野引用
2. ref不能为常量(数字等const类型数据),常量作为参数会导致权限放大,编译器报错。

这说明引用并不是绝对安全的

  • 注意2:注意初始化列表的初始化顺序!
    初始化列表的初始化顺序是成员变量的定义顺序,与在初始化列表的先后顺序无关!
    以下为错误用例:
    在这里插入图片描述
    由于A类中成员变量的定义顺序为_a2 _a1 ,所以先对_a2进行初始化,再对_a1进行初始化,而不是初始化列表中的顺序(先_a1再_a2)。
    所以初始化列表中变量的顺序最好和成员变量的顺序保持一致,防止出现初始化错误。

  • 注意3:初始化列表并不能代替函数体赋值
    以下功能等初始化列表并不能很好实现:

  1. 用malloc开辟空间(虽然初始化列表括号里能使用malloc,但初始化列表并不能对空指针进行检查)
  2. 对数组进行初始化并检查空指针
  3. 动态开辟二维数组(循环+指针数组+动态开辟空间)

总有工作是初始化列表无法很好完成的,但建议优先考虑使用初始化列表
【总结】

  1. 每个成员变量在初始化列表中最多出现一次(初始化只能初始化一次)
  2. 类中包含以下成员,必须放在初始化列表位置进行初始化:
  • 引用成员变量
  • const成员变量
  • 自定义类型成员(该类没有默认构造函数)
  1. 尽量使用初始化列表初始化,因为不管你是否使用初始化列表,对于自定义类型成员变量,一定会先使用初始化列表初始化。
  2. 成员变量在类中声明次序就是其在初始化列表中的初始化顺序,与其在初始化列表中的先后次序无关

explicit关键字

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

  • 在C++中,将整形赋值给对象是可以的。
    如:A aa = 2;
    这里的整形2发生了隐式类型转换(整形转换为自定义类型),既然发生了类型转换就一定会产生临时变量(这里产生了A类型的临时变量,再进行拷贝构造)。
    过程:2构造一个A的临时对象,临时对象再拷贝构造aa。但是构造之后再进行拷贝构造过程较为繁琐,有些编译器会对这个过程进行优化,优化成直接进行构造。(编译器会优化连续的构造函数+拷贝构造)
    以VS2019为例:
    在这里插入图片描述
    两者调用的都是构造函数,说明编译器进行了优化。
    同一行一个表达式(分开写不会优化)中连续的构造+拷贝构造,优化为合二为一(也有合三为一)(《深度探索C++对象模型》)
    【总结】
  1. 隐式类型,连续构造+拷贝构造->优化为直接构造
  2. 一个表达式中,连续构造+拷贝构造->优化为一个构造
  3. 一个表达式中,连续拷贝构造+拷贝构造->优化为一个拷贝构造
  4. 一个表达式中,连续拷贝构造+赋值重载->无法优化
  • 问题1:既然直接进行构造函数那还会产生临时变量吗?
    在这里插入图片描述
    286行代码正确,而287行代码错误,说明仍然产生了临时变量。
    所以我们可以理解为编译器的优化是直接构造函数,但语法上仍产生了临时变量。
  • 问题2:为什么C++能实现对整形的隐式类型转换成自定义类型?
    举例:在string类中可以将字符串转化为string类,如果要将字符串插入到链表中可以直接将字符串作为string类的参数(隐式类型转换)。
  • 如果我们不想让隐式类型转换发生我们可以用explicit关键字
    将explicit关键字加在只有一个参数的构造函数的开始,来防止发生隐式类型转换。
    在这里插入图片描述

static成员

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

成员变量和静态成员变量区别

成员变量属于每一个类对象,存储在对象里面。
静态成员变量属于类,类的每一个对象共享。生命周期为全局,存储在静态区
如果对象里有静态成员变量那么它必须在类外面定义,因为静态成员变量是共享的,不是属于单独的具体的一个类,如果在类里面定义可能会发生多次初始化从而报错。
定义方式:
在这里插入图片描述
按理来说在类外面不能访问私有变量,这是特例。
如果在类外要访问私有的静态变量,可以用Get成员函数,或者用友元函数,或者改为public

成员函数和静态成员函数区别

成员函数:有this指针,
静态成员函数:无this指针,指定类域和访问限定符(. 和** :: ** 都可以)就可以访问(可以突破类域)
由于静态成员函数没有this指针,所以无法访问非静态的成员变量(无法指定某个类),但可以访问静态成员变量

【总结】

  1. 静态成员为所有类对象所共享,不属于某个具体的实例
  2. 静态成员变量必须在类外定义,定义时不添加static关键字
  3. 类静态成员即可用类名::静态成员或者对象.静态成员来访问
  4. 类里面的静态成员不能给缺省值
  5. 静态成员函数没有隐藏的this指针,不能访问任何非静态成员
  6. 静态成员和类的普通成员一样,也有public、protected、private3种访问级别,也可以具有返回值

【问题】

  1. 静态成员函数可以调用非静态成员函数吗?(不能)
  2. 非静态成员函数可以调用类的静态成员函数吗?(可以)
C++11 的成员初始化新玩法。

C++11支持非静态成员变量在声明时进行初始化赋值,但是要注意这里不是初始化,这里是给声明的成员变量缺省值。

友元

友元分为:友元函数和友元类
友元提供了一种突破封装的方式,有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

友元函数

形式friend + 函数声明;
友元函数并不是类成员,因此声明的位置不固定(一般在类开头声明)
友元函数在之前的博客【C++】类与对象(2补充运算符重载,const成员)(博客链接)中流插入流提取中有提到:
我们尝试去重载operator<<,然后发现我们没办法将operator<<重载成成员函数。因为cout的输出流对象和隐含的this指针在抢占第一个参数的位置。this指针默认是第一个参数也就是左操作数了。但是实际使用中cout需要是第一个形参对象,才能正常使用。所以我们要将operator<<重载成全局函数。但是这样的话,又会导致类外没办法访问成员,那么这里就需要友元来解决。operator>>同理

友元函数:可以直接访问类的私有成员,它是定义在类外部的普通函数,不属于任何类,但需要在类的内部声明,声明时需要加friend关键字。
说明:友元函数并不是特别好,因为友元函数一定程度上破坏了类的封装,(像Java这样的语言不太推荐用友元Java常用get成员函数和set成员函数)

【总结】

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

形式friend class + 类名;
友元类的所有成员函数都可以是另一个类的友元函数,都可以访问另一个类中的非公有成员。

  • 友元关系是单向的,不具有交换性。
    比如Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time
    类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
  • 友元关系不能传递
    如果B是A的友元,C是B的友元,则不能说明C时A的友元。
内部类(Java常用)

概念及特性
概念:如果一个类定义在另一个类的内部,这个内部类就叫做内部类。注意此时这个内部类是一个独立的类,它不属于外部类,更不能通过外部类的对象去调用内部类。外部类对内部类没有任何优越的访问权限。
注意:==内部类就是外部类的友元类。==注意友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员。但是外部类不是内部类的友元。(也就是内部类可以访问外部类成员,而外部类不能访问内部类成员)
内部类运用示例:
在这里插入图片描述
内部类用于

【总结】:

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

在这里插入图片描述
如果只需要调用一次类里面的成员函数,可以使用匿名对象来访问成员函数,如果需要多次访问成员函数就不能使用匿名对象,匿名对象调用后就立即销毁(生命周期只在当前行,有名对象生命周期在局部域)。
注意无论是有参调用构造函数还是无参调用构造函数都必须加括号。
在这里插入图片描述

A.print(10);是错误的写法,因为==类型不能调用函数。==匿名对象和普通对象传参一样,只是少了名字。

const延长匿名对象的生命周期

匿名对象是可以被引用的,但需要加const(匿名对象具有常性!!!),const延长了匿名对象的生命周期,使其不会变为野引用。
在这里插入图片描述

  • 301行正确,302行错误(权限放大)。
  • 之后顺序表和链表等会用到const延长匿名对象生命周期这一特性。(push一个匿名对象,作为push函数中的参数:const string& s)
理解封装

C++是基于面向对象的程序,面向对象有三大特性即:封装、继承、多态
C++通过类,将一个对象的属性与行为结合在一起,使其更符合人们对于一件事物的认知,将属于该对象的所有东西打包在一起;通过访问限定符选择性的将其部分功能开放出来与其他对象进行交互,而对于对象内部的一些实现细节,外部用户不需要知道,知道了有些情况下也没用,反而增加了使用或者维护的难度,让整个事情复杂化


【C++】类与对象入门部分完结

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

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

相关文章

《操作系统》——进程与线程

在上一期博客中&#xff0c;我们学习了关于操作系统中计算机系统概述的基本知识。今天&#xff0c;我将带领学习的是关于操作系统中一个非常重要的概念——进程与线程&#xff01;&#xff01;&#xff01; 目录 前言 &#xff08;一&#xff09;进程的基本概念和特征 1、进…

[golang gin框架] 33.Gin 商城项目- 集成支付宝微信支付、生成支付二维码、监听处理异步通知跳转到订单页面

一.界面展示 当用户点击去支付时,请求支付界面,并 展示对应订单相关数据,以及 支付方式相关操作,点击对应的支付方式,进行支付操作 该界面对应的功能: 1.进入该界面,后台逻辑判断: 是否存在该订单,如果不存在,则跳转到购物车页面;如果存在,则获取对应订单相关数据,并 渲染到页面…

0511课后作业(C高级)

1.编写一个名为myfirstshell.sh的脚本&#xff0c;它包括以下内容。 1、包含一段注释&#xff0c;列出您的姓名、脚本的名称和编写这个脚本的目的 2、和当前用户说“hello 用户名” 3、显示您的机器名 hostname 4、显示上一级目录中的所有文件的列表 5、显示变量PATH和HOM…

iOS播放与编辑HDR视频

在iPhone12发布后&#xff0c;支持使用Dolby Vision来录制HDR视频。至此&#xff0c;升级到iOS14.1系统后&#xff0c;已经支持录制、播放、编辑和导出HDR视频。接下来&#xff0c;让我们一起探索HDR视频的各种操作。 一、HDR视频边编辑边预览 1、Profile与Level HDR视频中&…

Java奠基】实现面向对象编程方法

目录 标准的JavaBean类 设计对象并使用 对象封装 this关键字 构造方法 要知道对象是一个又一个能帮助我们解决问题的东西&#xff0c;但是这些东西并不是凭空出现的&#xff0c;需要我们根据设计图来进行制造&#xff0c;而这些一个一个的设计图就是一个一个的类。 标准的…

ChatGPT分销版多开v3.9.1-新增 语音识别和绘画多个引擎-已测试

众所周知ChatGPT在国内是无法正常使用的 而我们模块要做的就是这一点让普通人使用上ChatGPT 或娱乐或作为生产力工具 当前ChatGPT是非常火的 但是国内环境复杂&#xff0c;所以机会来了。。。 ChatGPT分销版多开v3.9.1&#xff1a;公众号H5版本 目前没反编译前端容易封号…

计算机网络-SNMP协议与pysnmp

1.概念 2.典型架构 3.snmp的信息交互 4.MIB 4.1常见MIB节点 5.SNMP管理模型 MIB位于被管理进程 6.SNMP的三个版本 6.1 SNMPv1 6.2 SNMPv2C 6.3 SNMPv3 6.3.1 SNMP3的基本操作 6.3.2 SNMP交互GET 6.3.3 SNMP交互-GETBULK 6.3.4 SNMP交互-SET 6.3.5 SNMP交互-trap 6.3.6 SNMP交…

【开源之夏 2023】欢迎报名 Dragonfly、Kata Containers、Nydus 社区项目!

开源之夏是由“开源软件供应链点亮计划”发起并长期支持的一项暑期开源活动&#xff0c;旨在鼓励在校学生积极参与开源软件的开发维护&#xff0c;促进优秀开源软件社区的蓬勃发展&#xff0c;培养和发掘更多优秀的开发者。 活动联合国内外各大开源社区&#xff0c;针对重要开…

Dubbo消费端源码深入分析(8)

目录 简介 过滤器 &#xff08;Filter&#xff09; 负载均衡接口 &#xff08;LoadBalance&#xff09; 容错接口 &#xff08;Cluster&#xff09; 源码分析 1. 获取Invoker过程 2. 获取动态代理对象proxy 3. 最后调用此动态代理对象的invoke方法 过滤器、容错组件、负…

基础IO(二)

磁盘 1.基础概念2.磁盘线性理解3.文件系统4.inode与文件名5.理解增删查改6.补充细节 &#x1f31f;&#x1f31f;hello&#xff0c;各位读者大大们你们好呀&#x1f31f;&#x1f31f; &#x1f680;&#x1f680;系列专栏&#xff1a;【Linux的学习】 &#x1f4dd;&#x1f4…

Chapter7:非线性控制系统分析(下)

第七章:非线性控制系统分析 Exercise7.11 设非线性系统结构图如下图所示,分析系统运动并计算自振参数。 解: 将 3 3 3个串联非线性环节进行等效合并,由于反馈通道饱和特性与前向通道饱和特性同时进入饱和状态,所以反馈通道的非线性环节相当于不起作用,将前向通道的另两…

【计算机视觉 | 自然语言处理】Hugging Face 超详细介绍和使用教程

文章目录 一、前言二、可以获得什么&#xff1f;三、入门实践3.1 帮助文档3.2 安装3.3 模型的组成3.4 BERT模型的使用3.4.1 导入模型3.4.2 使用模型3.4.2.1 tokenizer 3.5 model3.6 后处理 一、前言 Hugging Face 起初是一家总部位于纽约的聊天机器人初创服务商&#xff0c;他…

URP渲染管线里面的摄像机用法

大家好&#xff0c;我是阿赵&#xff0c;这里继续讲一下URP渲染管线。 这次要讲的是URP渲染管线里面的摄像机用法 之前介绍过&#xff0c;URP摄像机和普通摄像机的属性显示上有比较大的变化&#xff1a; 接下来从用法上来说明一下&#xff1a; 1、多个摄像机的处理变化 多个…

unity UGUI系统梳理 -交互组件

概述 unity 中的交互组件可用于处理交互&#xff0c;例如鼠标或触摸事件以及使用键盘或控制器进行的交互 1、按钮 (Button) Button详解 2、开关 (Toggle) Background&#xff1a;背景图片&#xff0c;控制toggle组件的背景颜色改变&#xff0c;从而展示此物体是否被选中的…

5.View的事件分发机制/事件处理机制原理分析

事件MotionEvent包含了哪几个? ACTION_DOWN 手指触碰到屏幕时触发,只会执行一次ACTION_MOVE 手指在屏幕上滑动出发,会执行多次ACTION_UP 手指抬起离开屏幕出发,只会执行一次ACTION_CANCEL 事件被上层拦截时会触发 父容器ViewGroup需要从子View手中抢夺分发的事件进行处理时,会…

【SCI】综合能源系统中热电联产、电制气和碳捕集系统的建模与优化(Matlab代码实现)

&#x1f4a5;&#x1f4a5;&#x1f49e;&#x1f49e;欢迎来到本博客❤️❤️&#x1f4a5;&#x1f4a5; &#x1f3c6;博主优势&#xff1a;&#x1f31e;&#x1f31e;&#x1f31e;博客内容尽量做到思维缜密&#xff0c;逻辑清晰&#xff0c;为了方便读者。 ⛳️座右铭&a…

Java 网络编程 —— 非阻塞式编程

线程阻塞概述 在生活中&#xff0c;最常见的阻塞现象是公路上汽车的堵塞。汽车在公路上快速行驶&#xff0c;如果前方交通受阻&#xff0c;就只好停下来等待&#xff0c;等到公路顺畅&#xff0c;才能恢复行驶。 线程在运行中也会因为某些原因而阻塞。所有处于阻塞状态的线程…

C++数据结构:哈希 -- unordered系列容器、哈希表的结构以及如何通过闭散列的方法解决哈希冲突

目录 一. unordered系列关联式容器 1.1 unrodered_map和unordered_set 综述 1.2 常见的接口函数&#xff08;以unordered_map为例&#xff09; 1.3 unordered系列与map和set的效率对比 二. 哈希表的底层结构 2.1 什么是哈希 2.2 哈希函数 2.3 哈希冲突 三. 通过闭散列的…

JavaEE(系列2) -- 多线程(创建多线程)

讲述下面的内容之前,先来回顾一下一个重要的知识点 进程和线程之间的区别 1.进程包括线程。 2.进程有自己独立的内存空间和文件描述符表。同一个进程中的多个线程之间&#xff0c;共享同一份地址空间和文件描述符表。 3.进程是操作系统资源分配的基本单位&#xff0c;线程是操作…

5.14学习周报

文章目录 前言文献阅读摘要介绍方法模型框架评价指标结果结论 时间序列预测总结 前言 本周阅读文献《A Hybrid Model for Water Quality Prediction Based on an Artificial Neural Network, Wavelet Transform, and Long Short-Term Memory》&#xff0c;文献主要提出了基于人…