C++类和对象(三):构造函数初始化、友元、匿名对象、内部类

2023-11-05

前言:这些知识点属于C++较为前期的内容,博主在今年刷笔试题的时候遇到多次,所以特地这这篇博客再复习了一下。



1.构造函数的初始化

在推导之前,关于初始化我们先达成一点共识:初始化只能一次(记住这点)

接着讨论一个问题,以下日期类构造函数里面的赋值语句到底是不是初始化?

class Date
{
public:
	Date(int year, int month, int day)
	{
		_year = year;
		_month = month;
		_day = day;
        _year = 9102;
	}

private:
	int _year;
	int _month;
	int _day;
};

答案很明显了,开头已经提到了初始化只能有一次,但是在这个构造函数里面,_year多次被赋初值。(证明这不是初始化还有另一个角度,如果我们的成员是必须要初始化的const,或者是引用,我们如果使用函数体内赋值,编译器会报错)。

初始化的话自然就是用到初始化列表了,需要注意的点只有一个:初始化顺序看什么?

class Date
{
public:
	Date(int& year, const int month, int day)
		:_year(year),
		 _month(month).
         _day(day)
		 
	{

	}

private:
    int _day;
    const int _month;
	int &_year;
};

初始化的顺序是按照参数在类中声明的顺序,与初始化列表的顺序无关,以上述代码为例,初始化顺序是day -> month -> year。

当类中包含以下成员的时候,必须要通过初始化列表初始化

  1. 引用成员变量
  2. const成员变量
  3. 自定义类型成员(该类没有默认构造函数,只有带参构造函数)

2.友元

这个选择题常考!

友元函数

友元函数是指某些虽然不是类成员却能够访问类的所有成员的函数。类授予它的友元特别的访问权。

友元函数需要在类内进行声明,声明时用friend关键字来修饰。

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

友元类

友元类的所有成员函数都是另一个类的友元函数,都可以访问另一个类中的隐藏信息(包括私有成员和保护成员),使用friend class来声明对应的类为友元类。

比如我们想在一个类中,访问其他类的所有私有成员,就可以通过友元类实现。

关于友元注意两点:

1.友元关系是单向的,不具有交换性。
Date为A的友元,可以访问A的私有成员,但是A并不能访问Date的

2.友元关系不能传递
如果B是A的友元,C是B的友元,则不能说明C时A的友元。

3.匿名对象

当我们需要使用一次某个对象,但是其他地方不再需要该对象的时候,如果我们直接构造一个对象使用,这无疑是一种很大的浪费,因为这个对象我们用了一次就扔了,而一个对象的生命周期是整个栈帧。

这时就需要用到匿名对象,匿名对象是一种临时的对象,它的生命周期只有使用它的那一行语句,执行完则立即销毁。

int main()
{
	Date d1;
	d1.Print(2020);
	//创建一个对象,生命周期为整个函数栈帧

	Date().Print(2020);
	//创建一个匿名对象,生命周期只有这一行语句,实行完则立即调用析构函数
}

对了,这里的匿名对象记得和隐式类型转换区分开,以下述代码为例:

Date d1(2020, 4, 24);
Date d2 = 2020;//C++98
Date d3 = { 2020, 4 }; //C++11
Date d4 = { 2020, 4, 24 }; //C+11

这里的d2, d3, d4明明类型和等号右边的数据类型都不一致,但是这四个对象最后的值一模一样,这就是“隐式类型转换”在悄悄的发挥作用!本质就是:

  1. 2020被隐式转换成了下面的形式,所以才能这样.
  2. d2 = Date temp(2020);

所以c++提供了关键字explicit用这个关键字修饰的函数就会禁止隐式类型的转化。当类的构造函数的声明和定义分别在两个文件里时,explicit只能写在构造函数的声明中,不能写在定义中。

4.内部类

如下代码中,B就是A的内部类,思考这两个类有什么关系?

class A
{
public:
    .......
  	.......
private:
	class B
	{
	public:
		.......
        .......

	private:
		.......
  		.......
	};
  .......
  .......
	
};

这个内部类其实是一个独立的类,它不属于外部类,外部类对它也没有任何权限,但是它同时还是外部类的友元类,可以通过外部类的对象参数来访问外部类的所有成员。

特性:

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

5.类的static成员

这个考点考过无数次。

对于用static修饰的成员函数,称为静态成员函数,成员变量称为静态成员变量。如果对于一个成员,对其以static修饰,此时这个成员就不再属于对象,而是属于这一整个类的所有对象。因为静态的成员的生命域不在类中,在静态区,所以静态的成员只能在类外初始化。

静态数据成员

定义格式:

static 类型名 静态数据成员名 ;

由于静态数据成员属于本类的所有对象共享,不属于特定类对象,因此在未产生类对象时作用域就可见,即:在未产生类的实例时,就可以对它进行操作。

初始化:

类型 类名 :: 静态数据成员 = 初始化值 ;

静态数据成员必须在类外初始化,类内也不可以初始化

静态数据成员必须在类定义体的外部定义,且只能定义一次。静态数据成员不能通过类的构造函数初始化,而是应该在定义时进行初始化。
保证对象正好定义一次的方法是,将static数据成员的定义放在包含类的非内联成员函数定义的源文件中。

// test.h
// 定义类
class Box
{
public:
	.......
  	.......
private:
	static double height;//静态函数的成员变量也得是静态变量,但是静态变量的赋值需要在类外进行赋值
};

//test.c
// 定义、初始化类的静态数据成员
double Box::height = 10;//初始化赋值放到类外,如果头文件和源文件分开,则初始化需要在源文件中进行

静态成员函数

定义格式:

static 返回类型 静态成员函数名 (参数表) ;

调用方式:

类名 :: 静态成员函数名 (实参表) ;
对象名 . 静态成员函数名 (实参表) ;

注意:

类外定义静态成员函数时,定义格式和普通成员函数定义格式相同,不再使用static修饰;
使用对象名和成员运算符(.)调用成员函数时,并非该函数属于某一对象,只是类与对象间的桥梁,为了能处理静态数据成员;

静态成员函数不能默认引用本类非静态数据成员的原因:

当调用一个对象的非静态成员函数时,系统会将该对象的起始地址赋予成员函数的this指针。然而,静态成员函数不属于对象,无this指针。所以静态成员函数不能访问类的默认非静态成员(非静态成员函数和非静态数据成员)

小结:

1.静态成员为所有类对象所共享,不属于某个具体的实例
2.静态成员变量必须在类外定义,定义时不添加static关键字
3.类静态成员即可用类名::静态成员或者对象.静态成员来访问
4.静态成员函数没有隐藏的this指针,不能访问任何非静态成员
5.静态成员和类的普通成员一样,也有public、protected、private3种访问别,也可以具有返回值
6.静态成员和全局变量虽然都存储在静态区,但是静态成员的生命周期只在本文件中,而全局变量不是

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++类和对象(三):构造函数初始化、友元、匿名对象、内部类 的相关文章

  • Qt - QProcess 不工作

    我尝试启动 Internet Explorer 所以我使用下面的代码 QProcess process new QProcess this QString temp C Program Files Internet Explorer iex
  • Exit() 时是否调用基本对象析构函数?

    我意识到这个问题已经出现过几次 但我试图获得上述问题的明确答案 但我不断遇到相互矛盾的信息 我需要知道的是 当我使用 exit 时 基本类对象是否被破坏 我知道需要删除动态内存 但我的意思更像是 include
  • 尝试了解使用服务打开对话框

    我已经阅读了有关使用 mvvm 模式打开对话框的讨论 我看过几个使用服务的示例 但我不明白所有部分如何组合在一起 我发布这个问题寻求指导 以了解我应该阅读哪些内容 以更好地理解我所缺少的内容 我将在下面发布我所拥有的内容 它确实有效 但从我
  • Environment.CurrentDirectory 与 System.IO.Directory.GetCurrentDirectory

    我正在编写一个 Net WinForms 并不断在调试和发布配置之间切换 并且有一些文件我需要任一配置才能访问 我想做的是将文件放在 BIN 文件夹中的公共目录中 这样它看起来像这样 MyProject Bin CommonFiles My
  • 传递 constexpr 对象

    我决定给予新的C 14的定义constexpr旋转并充分利用它 我决定编写一个小的编译时字符串解析器 然而 我正在努力保持我的对象constexpr将其传递给函数时 考虑以下代码 include
  • 在 C# 中,如何根据在 gridview 行中单击的按钮引用特定产品记录

    我有一个显示产品网格视图的页面 该表内有一列 其中有一个名为 详细信息 的超链接 我想这样做 以便如果用户单击该特定产品的详细信息单元格 将打开一个新页面 提供有关该产品的更多信息 我不确定如何确定哪个Product记录链接的详细信息以及我
  • 如何在 C# Designer.cs 代码中使用常量字符串?

    如何在 designer cs 文件中引用常量字符串 一个直接的答案是在我的 cs 文件中创建一个私有字符串变量 然后编辑 Designer cs 文件以使用此变量 而不是对字符串进行硬编码 但设计者不喜欢这样抛出错误 我明白为什么这行不通
  • 获取没有显式特征的整数模板参数的有符号/无符号变体

    我希望定义一个模板类 其模板参数始终是整数类型 该类将包含两个成员 其中之一是类型T 另一个作为类型的无符号变体T 即如果T int then T Unsigned unsigned int 我的第一直觉是这样做 template
  • 是否使用 C# 数据集? [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我对 C 中的数据集概念有点困惑 编码 ASP NET 站点 但这并不重要 在我的阅读中 我了解到它们 本质上 用作我的应用程序和我的
  • 从网页运行 ClickOnce 应用程序,无需用户操作

    我们有一个基于 Java 的 Web 应用程序以及用 C 编写的相同应用程序 如果 java 检查器发现客户端计算机上没有安装 Java 则应该运行该应用程序 这个想法是运行 C 单击一次 http en wikipedia org wik
  • 在 .NET MAUI 中实现 TouchTracking

    我一直致力于将我们的应用程序从 Xamarin Forms 迁移到 NET MAUI 我们的应用程序几乎没有绘图功能 用户可以用手指进行绘图 我们用了TouchTrackingXamarin Forms 中的 nuget 包 但与 NET
  • 已发布的 .Net Core 应用程序警告安装 .Net Core,但它已安装

    我制作了一个 WPF 和控制台应用程序 供某人在我无法访问的私人服务器上使用 我使用 Visual Studio 2019 的内置 发布向导 来创建依赖于框架的单文件应用程序 当该人打开 WPF 应用程序时 他们会看到标准警告 他们单击 是
  • 从 C# 使用 Odbc 调用 Oracle 包函数

    我在 Oracle 包中定义了一个函数 CREATE OR REPLACE PACKAGE BODY TESTUSER TESTPKG as FUNCTION testfunc n IN NUMBER RETURN NUMBER as be
  • 将二变量 std::function 转换为单变量 std::function

    我有一个函数 它获取两个值 x 和 y 并返回结果 std function lt double double double gt mult double x double y return x y 现在我想得到一个常量 y 的单变量函数
  • 将 Lambda 表达式树与 IEnumerable 结合使用

    我一直在尝试了解有关使用 Lamba 表达式树的更多信息 因此我创建了一个简单的示例 这是代码 如果作为 C 程序粘贴到 LINQPad 中 它可以工作 void Main IEnumerable
  • Visual Studio 2015 - Web 项目上缺少共享项目参考选项卡

    我从 MSDN 订阅升级到 Visual Studio 2015 因为我非常兴奋地阅读有关共享项目的信息 当我们想要做的只是重用代码时 不再需要在依赖项中管理 21382 个 nuget 包 所以我构建了一个测试共享项目 其中包含一些代码
  • 了解 Lambda 表达式和委托 [关闭]

    Closed 这个问题需要多问focused help closed questions 目前不接受答案 我已经尝试解决这个问题很长一段时间了 阅读在线博客和文章 但到目前为止还没有成功 什么是代表 什么是 Lambda 表达式 两者的优点
  • EntityFramework 6.0.0.0 读取数据,但不插入

    我创建了一个基于服务的数据库 folderName gt Add New Item gt Data gt Service based Database文件到 WPF 应用程序中 然后我用过Database First方法并创建了Person
  • 在 System.Type 上使用条件断点时出错

    这是函数 public void Init System Type Type this Type Type BuildFieldAttributes BuildDataColumns FieldAttributes 我在第一行设置了一个断点
  • 是否允许全局静态标识符以单个 _ 开头?

    换句话说 可能static 文件范围 全局变量恰好以一个下划线开头 而不会产生与 C 实现发生名称冲突的可能性 https www gnu org software libc manual html node Reserved Names

随机推荐

  • Springboot使用redis(订单倒计时5分钟不支付自动取消),不会出现网上所说的空指针

    1 下载windows版本的redis 链接是 https github com microsoftarchive redis releases 1 1 开启redis过期提醒 linux也是差不多 2 引入jar包
  • 线段树(四类)

    文章目录 线段树 模板题 P4513 小白逛公园 https www luogu com cn problem P4513 P3372 模板 线段树 1 https www luogu com cn problem P3372 P3373
  • layui获取多选框中的值

    HTML
  • 【vue】 前端vue2 全局水印效果

    最近写项目遇到一个需求 全局显示水印 不管在哪个路由都要显示 想要实现的效果 新建shuiyin js文件 定义水印函数 const addWatermark container document body 水印添加到的容器 默认为 bod
  • C++自学记录(函数基础)

    目录 函数基础 编写函数 调用函数 形参和实参 函数的形参列表 函数的返回类型 局部对象 全局对象和局部变量 的区别 自动对象 局部静态变量 函数声明 在头文件中进行函数声明 分离式编译 函数基础 函数定义包含部分 返回类型 return
  • CTF每日一题之图片信息查看

    题目的要求大概就是从图片信息里查看答案 题目地址 http www wechall net challenge training stegano1 index php 直接图片另存到本地 然后使用文本模式打开图片 发现密码 然后复制下来 提
  • conda 导出环境文件的方法(文件方法)

    conda 导出环境文件的方法 文件方法 1 导出环境 conda env export gt environment yml 2 在新机器上重现环境 conda env create f environment yml 此时只有conda
  • python实现10大排序算法详细介绍及排序思想介绍

    什么是排序 排序是按关键字的非递减或者非递增顺序对一组记录重新进行排列的操作 1 排序的稳定性 通俗地讲 就是排序前 Ri 在 Rj前面 排序后Ri仍领先于Rj 则说明是稳定的 Ri
  • 基于WSAAsyncSelect模型的服务端和客户端设计(MFC)

    目录 1 效果展示 1 1 服务器和客户端界面展示 1 2 一对一之间通信的功能展示 1 3 一对多之间通信的功能展示 2 知识预备 2 1 WSAAsyncSelect模型介绍 2 2 WSAAsyncSelect模型的过程图 2 3 与
  • 深入浅出AXI协议(3)——握手过程

    一 前言 在之前的文章中我们快速地浏览了一下AXI4协议中的接口信号 对此我们建议先有一个简单的认知 接下来在使用到的时候我们还会对各种信号进行一个详细的讲解 在这篇文章中我们将讲述AXI协议的握手协议 二 握手协议概述 在前面的文章中我们
  • vue-amap infowindow基础用法

  • ChatGPT中的Token:了解聊天模型的基本单位

    文章目录 ChatGPT中的Token是什么 ChatGPT中有三种类型的Token 如何获取ChatGPT的Token Token在ChatGPT平台中有什么作用 Token是否会过期 如果过期了怎么办 创作者 全栈弄潮儿 个人主页 全栈
  • 面试官:ThreadLocal 搭配线程池时为什么会造成内存泄漏?

    您好 我是路人 更多优质文章见个人博客 http itsoku com ThreadLocal是什么 ThreadLocal是一个本地线程副本变量工具类 主要用于将私有线程和该线程存放的副本对象做一个映射 各个线程之间的变量互不干扰 在高并
  • 基础篇--Web容器学习路径

    在开篇词里我提到要成长为一名高级程序员或者架构师 我们需要提高自己知识的广度和深度 你可以先突破深度 再以点带面拓展广度 因此我建议通过深入学习一些优秀的开源系统来达到突破深度的目的 我会跟你一起在这个专栏里深入学习 Web 容器 Tomc
  • Linux 管道命令系列 一 熟悉PIPE

    什么是管道命令 但就名称来看应该分为 管道 和 命令 管道 先来看管道 我是这样理解管道的 管道就是在两个命令之间建立连接 也就是前一个的命令的标准输出结果是后一个命令的标准输入 这个过程就是通过管道来实现的 管道命令执行流程 管道使用的是
  • Linux Ubuntu20.04 版本下安装 GAMMA 2020版 安装步骤 安装教程

    GAMMA 2020版 安装步骤 安装教程 1 解压GAMMA文件 设置环境变量 1 1 解压压缩包 选择解压压缩包的路径 建议的文件路径为 usr local 从terminal进入该路径 cd usr local GAMMA安装包一般是
  • GitHub 标星 2.5K+,U^2-Net 跨界肖像画,完美复刻人物细节!

    来源 Jack Cui 头图 CSDN下载自视觉中国 今年提出的 U 2 Net 显著性检测算法 刷爆了 reddit 和 twitter 号称是 2020 年 地表最强 的静态背景分割算法 可以看下效果 你以为今天要讲分割 错 U 2 N
  • java 子类实例化过程_Java子类实例化的过程

    继承 class Work public Work System out println 父类中的方法 class Worker extends Work public Worker System out println 子类中的方法 cl
  • 【Go mod操作命令大全】

    Go mod操作命令大全 一 基础理论 Go mod其实就是一个Modules 关于Modules的官方定义为 Modules是相关Go包的集合 是源代码交换和版本控制的单元 go命令直接支持使用Modules 包括记录和解析对其他模块的依
  • C++类和对象(三):构造函数初始化、友元、匿名对象、内部类

    前言 这些知识点属于C 较为前期的内容 博主在今年刷笔试题的时候遇到多次 所以特地这这篇博客再复习了一下 文章目录 1 构造函数的初始化 2 友元 3 匿名对象 4 内部类 5 类的static成员 静态数据成员 静态成员函数 1 构造函数