C++类和对象(下)

ops/2024/11/20 10:35:51/

文章目录

  • 1. 初始化列表
    • 1.1 什么是初始化列表
    • 1.2 为什么要引入初始化列表
    • 1.3 初始化列表如何写
      • 1.3.1 显式写初始化列表
      • 1.3.2 隐式写初始化列表
        • 1.3.2.1 不声明缺省值
        • 1.3.2.2 声明缺省值
      • 1.3.3 初始化列表总结
  • 2.类型转换
    • 2.1 内置类型与自定义类型转换
    • 2.2 自定义类型间的转换
    • 2.3 构造函数被explicit修饰
  • 3. 友元
    • 3.1 友元函数
    • 3.1 友元类
  • 4.static成员
    • 4.1 static修饰成员变量
    • 4.2 static修饰成员函数
  • 5. 内部类
  • 6. 匿名对象
    • 6.1 匿名对象解析
    • 6.2 匿名对象生命周期延长

1. 初始化列表

1.1 什么是初始化列表

初始化列表,是所有成员变量定义初始化的地方(此处的定义不再开空间,在对象创建时,空间便已开辟)。
初始化列表与构造函数结合,调用构造函数时,先走初始化列表,再走构造函数体。

初始化列表的格式如下:
在这里插入图片描述

1.2 为什么要引入初始化列表

引入初始化列表,主要是考虑到两类特殊情况:

  1. 自定义类的成员变量不含默认构造。C++规定,自定义类的对象在创建时就要初始化,即调用构造函数。而自定义类的成员变量会调用它的默认构造,但有些时候,不存在默认构造,此时该成员变量的初始化就会出现问题,这时便要使用初始化列表。
  2. const修饰的内置类型成员变量。这类成员变量同样要在定义的时候初始化,一旦初始化,便不可更改,否则会报错。而初始化列表,可以理解为变量定义并初始化的地方,所以这些被const修饰的内置类型成员变量,必须在初始化列表中初始化。

1.3 初始化列表如何写

初始化列表可以显式写,也可以隐式写。

1.3.1 显式写初始化列表

显式写初始化列表时,有以下三点需要注意:

  1. 每个成员变量在初始化列表中只能出现一次,不能重复出现
  2. 在初始化列表中,成员变量初始化的顺序并不是按照初始化列表中排列的顺序,而是按照成员变量声明的顺序,更准确地来说,是按照成员变量在内存中的存储顺序(先声明的,存储在前;后声明的,存储在后),其中先声明的,先初始化,后声明的,后初始化。所以,考虑到这点,成员变量在初始化列表的顺序应尽量与其声明顺序保持一致。
  3. 若成员变量中含有以下三类:const修饰的内置类型,引用,无默认构造的自定义类型——这三类,在未声明缺省值时,一定要显式在初始化列表中写出。

在这里插入图片描述

1.3.2 隐式写初始化列表

1.3.2.1 不声明缺省值

在不声明缺省值的情况下,能够不在初始化列表中写出的成员变量只有不被const修饰的内置类型成员变量以及含默认构造的自定义类型成员变量。 此时,这些成员变量虽然没有写出,但本质上依旧会走初始化列表——至于这时,初始化列表如何对这些成员变量进行初始化,C++是没有规定的,看编译器。

1.3.2.2 声明缺省值

在声明缺省值的情况下,所有的成员变量都可以不在初始化列表中写出。这个缺省值的作用是,若某个成员变量未在初始化列表中写出时,也就是程序员未主动对该成员变量初始化,此时,初始化列表便用该缺省值对该成员变量进行初始化。
在这里插入图片描述

需要注意的是,缺省值只用于未显式在初始化列表中写出的成员变量,显式在初始化列表中初始化的成员变量,用显式给出的值进行初始化。

在这里插入图片描述

1.3.3 初始化列表总结

我们在写初始化列表时,尽量保持形式的一致,即对于成员变量,要么全部显式初始化,要么全部给缺省值,隐式初始化,在允许的情况下,尽量不要混着写。

2.类型转换

内置类型与内置类型之间存在类型转换,同样,内置类型与自定义类型之间,自定义类型之间也存在类型转换,而这个类型转换,本质上是通过类的构造函数实现的。

2.1 内置类型与自定义类型转换

在创建一个类的对象时,往往可以看到下面的创建方式:
在这里插入图片描述
这种对象的初始化方式并不是直接调用构造函数初始化那么简单。
实质上,这中间存在一个临时对象的过渡。首先,编译器会生成一个AA类的临时对象,并将1传给该临时对象的构造函数进行初始化;然后,这个临时对象再通过拷贝构造,对我们创建的AA类对象sample进行初始化。所以,实际上有两个过程:调用普通构造,然后再调用拷贝构造。但实际上,编译器对于“构造+拷贝构造”会优化为直接构造,即直接将1传给构造函数,对sample进行初始化。

注:当构造函数需要多个参数时,使用花括号,如下所示:
在这里插入图片描述

2.2 自定义类型间的转换

自定义类型间的转换,同样借助类的构造函数实现。类型转换的过程同上,同样是构造+拷贝构造,同样会被编译器优化为直接构造
在这里插入图片描述

同上,当构造函数需要多个参数时,使用花括号:
在这里插入图片描述

2.3 构造函数被explicit修饰

构造函数被explicit修饰时,此时就不再支持隐式类型转换,但显式类型转换仍然支持。

在这里插入图片描述

3. 友元

友元的关键字为friend,分为两种:友元函数和友元类。

3.1 友元函数

友元函数的声明,目的是为了在类外访问类设置为私有的成员变量,更准确地说,一个类的友元函数可以访问这个类中所有的成员。
但值得注意的是,友元函数仅是声明为友元,它不会使得这个函数变为该类的成员函数。同时,友元声明可以放在一个类的任何地方,放在类的何处对友元声明无影响,但我们一般习惯将友元声明放在类的开头。

在这里插入图片描述

3.1 友元类

一个类也可以声明为另一个类的友元,尤其当一个类中要频繁地用到另一个类中的成员,此时声明为友元类,会带来极大的方便。

需要注意的是,友元类的关系是单向的,且不具备传递性。举个例子,A是B的友元,但B不是A的友元;再举个例子,A是B的友元,B是C的友元,但A不是C的友元。所以,看友元类,关键就是看哪个类在哪个类中声明为友元,重点看声明。

在这里插入图片描述
但是,凡事有利必有弊。友元虽然很方便,但还是不宜多用的,因为声明为友元会增加耦合度,破坏了类的封装性。

4.static成员

4.1 static修饰成员变量

static修饰的成员变量为静态成员变量,它不为某个对象私有,而是为该类实例化出的所有对象共有,这就决定了静态成员变量的几个特性:

  1. 静态成员变量放在静态区,而不是放在某个对象中,因此在计算类的大小时,静态成员变量不包含在内。
  2. 静态成员变量定义初始化不通过初始化列表,所以其必须在类外定义初始化,类中所写,仅为静态成员变量的声明。
  3. 静态成员变量仍是类的成员变量,仍然受到public/private/protected的影响,允许类外访问时,仍要突破类域,才可访问——两种方式突破类域:使用域作用限定符或使用成员访问操作符。
    在这里插入图片描述

4.2 static修饰成员函数

static修饰成员函数,即为静态成员函数,此函数无this指针,因而致使有以下几个特性:

  1. 静态成员函数无this指针,导致此函数只能访问类中的静态成员变量,而非静态的成员变量无法访问。
  2. 静态成员函数仍是类的成员函数,仍然受到public/private/protected的影响,允许类外访问时,仍要突破类域,才可访问——两种方式突破类域:使用域作用限定符或使用成员访问操作符。

5. 内部类

一个类定义在另外一个类中,此时,我们把这个类称为内部类。内部类有以下几个特性:

  1. 内部类默认为外部类的友元类,可以自由访问外部类的成员。
  2. 内部类受到外部类中public/private/protected的限制,可以通过private将内部类限制为私有内部类。如过不是私有内部类的话,即允许外部类外使用,内部类需要通过域作用限定符才可以使用。
    在这里插入图片描述
  3. 内部类本质上仍是一个独立类,计算外部类大小时,并不将内部类计算在内。同样,使用外部类实例化对象时,并不会在该对象内部再实例化出一个内部类对象。

总的来说,内部类是一种封装,如果A类实现出来就是为给B类使用,我们就可以将A类定义为B类的内部类,而且最好是私有内部类,B类外无法使用A类。从这个意义上讲,内部类一定程度上可看作友元类声明的优化——内部类维护了封装,友元类破坏了封装。

6. 匿名对象

C++中对象有两种:有名对象和匿名对象。有名对象即有变量名,匿名对象即无变量名。

6.1 匿名对象解析

在这里插入图片描述
匿名对象的生命周期只在当前语句,一旦当前语句执行完,进入下条语句时,匿名对象便会析构。

6.2 匿名对象生命周期延长

我们可以使用const引用来延长匿名对象的生命周期,至于为什么要加const,这是因为匿名对象具有常性。

在这里插入图片描述
其实严格来说,匿名对象生命周期延长后,已是一个有名对象,只不过该有名对象对应的内存空间即为匿名对象对应的内存空间。


http://www.ppmy.cn/ops/135210.html

相关文章

Python 正则表达式进阶用法:边界匹配

Python 正则表达式进阶用法:边界匹配 正则表达式是一种强大的工具,用于处理文本中的模式匹配。它广泛应用于文本查找、替换、数据清洗等任务。在学习了正则表达式的基础知识后,掌握更高级的用法将使得正则表达式的应用更加灵活。边界匹配&am…

2.5D视觉——Aruco码定位检测

目录 1.什么是Aruco标记2.Aruco码解码说明2.1 Original ArUco2.2 预设的二维码字典2.3 大小Aruco二维码叠加 3.函数说明3.1 cv::aruco::detectMarkers3.2 cv::solvePnP 4.代码注解4.1 Landmark图说明4.2 算法源码注解 1.什么是Aruco标记 ArUco标记最初由S.Garrido-Jurado等人在…

开源控件:Qt/C++自定义异形窗口和颜色选择器 【工程源码联系博主索要】

使用 Qt 和 C 实现一个异形窗口和自定义颜色选择器的过程。 1. CustomShapeWidgetUi 类 该类实现了一个具有自定义形状和颜色选择功能的窗口。 构造函数 CustomShapeWidgetUi CustomShapeWidgetUi::CustomShapeWidgetUi(const QString &imagePath, QDialog *parent): QD…

【GNU】addr2line

1、什么是addr2line addr2line 是 GNU Binutils 工具集中的一个命令行工具&#xff0c;用于将程序中的地址转换为源代码中的文件名和行号。它在调试和问题定位中非常有用&#xff0c;尤其是在处理崩溃或 core dump 时。 2、常用选项 选项功能-e <file>指定目标文件&am…

农村生活污水排水监测系统:助力乡村生态环境建设

在广袤的农村大地&#xff0c;清新的空气、绿色的田野和潺潺的溪流共同构成了美丽的乡村画卷。然而&#xff0c;随着农村经济的发展和生活水平的提高&#xff0c;农村生活污水的排放问题日益凸显&#xff0c;成为影响乡村生态环境的一个重要因素。为了有效解决这一问题&#xf…

全新UI H5购物商城系统存在前台任意文件上传漏洞

免责声明: 本文旨在提供有关特定漏洞的深入信息,帮助用户充分了解潜在的安全风险。发布此信息的目的在于提升网络安全意识和推动技术进步,未经授权访问系统、网络或应用程序,可能会导致法律责任或严重后果。因此,作者不对读者基于本文内容所采取的任何行为承担责任。读者在…

移动端web页面调用原生jsbridge的封装

为了统一android端和ios端调用原生jsbridge方法统一&#xff0c;且web端不需要使用callback方式接收回调&#xff0c;特封装了以下js工具类&#xff1a; // 全局回调管理器 window.CallbackManager {callbacks: new Map(),registerCallback: function (callbackId, callback)…

小程序-基于java+SpringBoot+Vue的小区服务管理系统设计与实现

项目运行 1.运行环境&#xff1a;最好是java jdk 1.8&#xff0c;我们在这个平台上运行的。其他版本理论上也可以。 2.IDE环境&#xff1a;IDEA&#xff0c;Eclipse,Myeclipse都可以。推荐IDEA; 3.tomcat环境&#xff1a;Tomcat 7.x,8.x,9.x版本均可 4.硬件环境&#xff1a…