当前位置: 首页 > article >正文

详说 类和对象

再探构造函数

我们上一篇文章也说了构造函数,但是还有一个 部分没有讲,就是构造函数的初始化列表。初始化列表这个挺麻烦的,大家认真理解一下。

1. 初始化列表的使⽤⽅式是以⼀个冒号开始,接着是⼀个以逗号分隔的数据成员列表,每个"成员变量"后⾯跟⼀个放在括号中的初始值或表达式

2.每个成员变量在初始化列表中只能出现⼀次,语法理解上初始化列表可以认为是每个成员变量定义初始化的地⽅。

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

4. C++11⽀持在成员变量声明的位置给缺省值,这个缺省值主要是给没有显⽰在初始化列表初始化的成员使⽤的。

5. 尽量使⽤初始化列表初始化,因为那些你不在初始化列表初始化的成员也会⾛初始化列表,如果这个成员在声明位置给了缺省值,初始化列表会⽤这个缺省值初始化。如果你没有给缺省值,对于没有显⽰在初始化列表初始化的内置类型成员是否初始化取决于编译器,C++并没有规定。对于没有显⽰在初始化列表初始化的⾃定义类型成员会调⽤这个成员类型的默认构造函数,如果没有默认构造会编译错误。

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

是不是很多,很晦涩难懂,我写代码来一段段解释大家就懂了。

我们首先要知道,每个类的成员变量是必须经过初始化列表的,但是其实我们有些变量是可以不初始化的,比如说我们定义了一个int变量,我们可以选择不初始化,编译器也不会报错,但是有三种情况,我们必须初始化,第一,经过const修饰的变量,他本来就是一个不会变的常量,我们不能改变他,所以必须初始化,第二,引用,引用就是别名,就是别的变量的另一个名字,那么,我们的引用也必然不能为空,一开始就要说好,这个引用是谁的引用。第三,没有默认构造函数的成员变量也必须要初始化。我将代码列举在下面,大家认真一一对应。

总结一下就是下图总结的三点: 我们还有一个点没有讲完,先看一段代码,请问输出的结果是什么?

我想很多人都会犯错误,觉得是选A对吗,其实选A 是错的,我们现将代码运行一下, 

答案选择D,因为我们初始化列表初始化的顺序是根据声明来的,声明先声明的是_a2,那就先初始化_a2,是不是就能说的通了? 

类型转换

1.C++⽀持内置类型隐式类型转换为类类型对象,需要有相关内置类型为参数的构造函数。

2.构造函数前⾯加explicit就不再⽀持隐式类型转换。

 3.类类型的对象之间也可以隐式转换,需要相应的构造函数⽀持。

我们上面说的这几点是类型转换的规则,如果觉得文字晦涩难懂,那么就看我下面展示的代码来辅助理解一下。

上面的代码呢,定义了A,B, Stack 这三种类类型,我们从main函数开始看,1之所以可以赋给A类型的对象是因为发生了隐式类型转换,中间产生了临时对象,而且我们编译器进行了优化工作,遇到连续构造和拷贝构造,欧化为直接构造。但是下下行,为什么要价格const呢?因为临时变量具有常性,给给引用以后权限放大了,所以才加的const。刚刚说的是单对象,要是多对象就是像下面那一行一样,需要一个花括号。

那么,祖师爷发明这个隐式类型转换就是为了用起来方便点吗,当然还有更加好的作用,就如我们下面所举的例子一样,右两种形式,如果是你会选择哪一种呢?我想都会选择下面这种吧。如果我们不想让编译器优化我们的代码怎么办?加个explicit就好了。

static成员

1.⽤static修饰的成员变量,称之为静态成员变量,静态成员变量⼀定要在类外进⾏初始化

2.静态成员变量为所有类对象所共享,不属于某个具体的对象,不存在对象中,存放在静态区。

3.⽤static修饰的成员函数,称之为静态成员函数,静态成员函数没有this指针。

4.静态成员函数中可以访问其他的静态成员,但是不能访问⾮静态的,因为没有this指针。

5.⾮静态的成员函数,可以访问任意的静态成员变量和静态成员函数。

6.突破类域就可以访问静态成员,可以通过类名::静态成员 或者 对象.静态成员 来访问静态成员变量和静态成员函数。

7.静态成员也是类的成员,受public、protected、private 访问限定符的限制。

8.静态成员变量不能在声明位置给缺省值初始化,因为缺省值是个构造函数初始化列表的,静态成员变量不属于某个对象,不⾛构造函数初始化列表。

先看一下规则,我们再用代码来一一解释。

改注释解释的都标注在上图了,至于为什么运行出来结果是033,那是因为每构造一次就会调用一次构造函数,我们这里构造了三个a1,a2,a3,所以打印出来的结果是3。 

那么我们用一道题目来好好了解一下这个static到底怎么用,我们看一下题目。

简单看一下,其实这一题并不难,不就是从1加到n吗,这个我们学习C语言的时候就写过很多次了,但是他的要求是不能使用循环和判断语句,是不是觉得这个要求很无理,就是故意为难我们,确实,但他想让你用别的办法,一种更加神奇的办法,就是我们上面学习的static和构造函数的巧妙结合就可以解决这个问题。

我们可以构造一个数组,一个变长数组,然后通过构造函数来达到我们的目的,其实思路也很简单,但是需要我们想到,看看代码能够让我们思路更加清晰。 

其实这里很核心的一个点就是每构造数组里面的一个数就会调用构造函数,利用这个巧妙的点,我们就能达到目的。

友元

我们友元在前面也说过,我们简单看一下规则。

1.友元提供了⼀种突破类访问限定符封装的⽅式,友元分为:友元函数和友元类,在函数声明或类声明的前⾯加friend,并且把友元声明放到⼀个类的⾥⾯。

2.外部友元函数可访问类的私有和保护成员,友元函数仅仅是⼀种声明,他不是类的成员函数。

3.友元函数可以在类定义的任何地⽅声明,不受类访问限定符限制。

4.⼀个函数可以是多个类的友元函数。

5.友元类中的成员函数都可以是另⼀个类的友元函数,都可以访问另⼀个类中的私有和保护成员。

6.友元类的关系是单向的,不具有交换性,⽐如A类是B类的友元,但是B类不是A类的友元。

7.友元类关系不能传递,如果A是B的友元, B是C的友元,但是A不是C的友元。

8.有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。

这就是友元的用法。 ​​​​​​​

这个是类友元,B 是 A 的类友元。 

内部类

1.如果⼀个类定义在另⼀个类的内部,这个内部类就叫做内部类。内部类是⼀个独⽴的类,跟定义在全局相⽐,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。

2.内部类默认是外部类的友元类。

3.内部类本质也是⼀种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使⽤,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地⽅都⽤不了。

我们看一下代码就知道了。

其实B还是单独的类,只不过定义在A 的里面就会被A 的访问限定符给限制,并且B 是A的默认友元。就是这样,也没什么复杂的。 

我们再用内部类的做法,把我们刚刚做的题再做一遍,其实思路没变,就是方式变了,这里不详细说明,看一下代码就明白了。

 


http://www.kler.cn/news/302520.html

相关文章:

  • element form rules 验证数组对象属性时如何写判断规则
  • 测试驱动开发(TDD)学习分享-下篇
  • Python知识点:如何使用Python进行图像批处理
  • MySQL中的约束
  • 系统分析师10:知识产权与标准化
  • 大模型中的多模态概念指的是什么
  • (计算机网络)应用层
  • Tomcat_使用IDEA开发javaWeb工程并部署运用
  • 爱普生相机SD卡格式化后数据恢复指南
  • C++速通LeetCode第5题-回文链表
  • 防止文件外发泄密有什么方法?这7防外发方式可以看下!
  • 数字化转型背景下低代码开发模式变革的研究
  • Excel图表生成:自动化创建与修改Excel图表的技术指南
  • 基于鸿蒙API10的RTSP播放器(五:拖动底部视频滑轨实现跳转)
  • pytorch torch.triu函数介绍
  • python实现进化算法
  • 在国产芯片上实现YOLOv5/v8图像AI识别-【4.4】RK3588网络摄像头推理后推流到RTSP更多内容见视频
  • 海思SD3403(21AP10, 108DC2910 )4K60 的 ISP 图像处理能力,4Tops INT8算力
  • 数据结构2 :双向链表和内核链表
  • mysql可重复读不能解决幻读吗?
  • linux————根据端口查找运行目录的三种方法
  • STM32内部闪存FLASH(内部ROM)、IAP
  • 信息安全工程师题
  • ASR(自动语音识别)识别文本效果的打分总结
  • 用Cri-O,Sealos CLI,Kubeadm方式部署K8s高可用集群
  • 【docker】了解什么是Docker
  • 欧洲麻花钻市场主要企业市场占有率及排名
  • Framework | 在Android中运行时获取顶层Activity并处理业务逻辑
  • 【测试】——自动化测试入门(Selenium环境搭建)
  • Golang | Leetcode Golang题解之第395题至少有K个重复字符的最长子串