【C++】类和对象⑤(static成员 | 友元 | 内部类 | 匿名对象)

🔥个人主页:Forcible Bug Maker

🔥专栏:C++

目录

前言

static静态成员

友元

友元函数

友元类

内部类

匿名对象

结语


前言

本篇主要内容:类和对象的一些知识点补充,包括static静态成员,友元,内部类等。

本篇基本上就是类和对象主要内容的收尾环节了,在前几篇中,已经将六大默认成员函数逐一做了介绍。接下来的内容就是补充一些语法和细节。那么开始我们今天的内容。

static静态成员

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

在C++中,static成员是类的成员,但它与类的任何特定对象实例都不关联。也就是说,不管创建了多少个类的对象,static成员都只有一个副本

static成员可以是成员变量成员函数。以下是关于static成员的一些关键点:

  1. 静态数据成员:静态数据成员在类的所有对象之间共享。这意味着无论创建了多少个对象,都只有一个静态数据成员的副本,且此副本存放在静态区。静态数据成员必须类定义外部进行初始化,且定义时不添加static关键字类中只是声明。如:

    class MyClass {  
    public:  static int count;  // 声明静态数据成员  
    };  int MyClass::count = 0;  // 在类定义外部初始化静态数据成员
  2. 静态成员函数:静态成员函数是类的一个成员函数,它可以在没有类的实例的情况下调用静态成员函数只能访问静态成员(包括静态成员变量和其他静态成员函数)。它们不能访问类的非静态成员,因为非静态成员需要类的实例才能存在,本质上说,静态成员函数没有隐藏的this指针,本身就是无法访问任何非静态成员的。如:

    class MyClass {  
    public:  static int count;  static void GetCount() {  count++;  // 可以访问静态数据成员  }  void doSomething() {  // 这里不能访问静态成员count,除非使用 MyClass::count  }  
    };
  3. 访问静态成员:你可以使用类名和作用域解析运算符( :: )来访问静态成员,无论是否创建了类的实例。例如,MyClass::count 和 MyClass::GetCount()

  4. 用途:静态成员常用于实现计数器(如上述示例中的count),或者当你想在类的所有实例之间共享某些数据时。静态成员函数通常用于执行与类本身相关但不依赖于任何特定对象实例的操作。

注:虽然静态成员与类的实例不关联,但它们仍然属于类的一部分,并类的访问访问限定符(如publicprotectedprivate)的影响

这里用一个面试题,引入关于静态成员变量的使用:实现一个类,计算程序中创建出了多少个对象:

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 << A::GetACount() << endl;A a1, a2;A a3(a1);cout << A::GetACount() << endl;
}

此份代码中,声明定义了静态成员变量_scount,当调用类的构造函数或拷贝构造时,静态成员变量_scount就会++计数,当调用析构函数时,就会对其逐一--,我们可以调用TestA()函数,来观察在这个过程中累计创建了多少对象。

注:静态成员函数不可以直接调用非静态成员变量,因为其没有this指针及现成的实例化对象;非静态成员函数可以直接调用类的静态成员变量,非静态成员函数本身并不依赖于特定的对象状态,它可以通过类的作用域直接访问静态成员变量

友元

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

友元函数

在前面Date类的博客中,曾提到过全局变量重载流插入(cout)和流提取(cin)操作符,由于插入和提取需要访问私有的成员变量,所以我们将这两个个全局函数设置为Date类的友元,如果感兴趣可以看看那篇博客关于友元的内容,这里就不赘述了。

地址放在这:【C++】日期类Date(详解)

说明:

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

友元类

友元类的所有成员函数都可以是另一个类的友元函数都可以访问另一个类中的非公有成员

友元类的一些特性:

  • 友元关系是单向的,不具有交换性。比如上述Time类和Date类,在Time类中声明Date类为其友元类,那么可以在Date类中直接访问Time类的私有成员变量,但想在Time类中访问Date类中私有的成员变量则不行。
  • 友元关系不能传递。如果C是B的友元, B是A的友元,则不能说明C时A的友元。
  • 友元关系不能继承。在继承位置再给大家详细介绍。

概念浅显易懂,用起来也不麻烦。

class Time
{// 声明日期类为时间类的友元类,则在日期类中就直接访问Time类中的私有成员变量friend class Date; 
public:Time(int hour = 0, int minute = 0, int second = 0): _hour(hour), _minute(minute), _second(second){}
private:int _hour;int _minute;int _second;
};
class Date
{
public:Date(int year = 1900, int month = 1, int day = 1): _year(year), _month(month), _day(day){}void SetTimeOfDate(int hour, int minute, int second){// 直接访问时间类私有的成员变量_t._hour = hour;_t._minute = minute;_t._second = second;}
private:int _year;int _month;int _day;Time _t;
};

在上述代码中,Date类被设置成了Time类的友元,所以在Date类的中成员函数中,可以直接使用Time类型的对象。

内部类

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

注:内部类就是外部类的友元类,参见友元类的定义,内部类可以通过外部类的对象参数来访问外部类中的所有成员但是外部类不是内部类的友元

特性

  1. 内部类定义在外部类的public、protected、private都是可以的。
  2. 注意内部类可以直接访问外部类中的static成员,不需要外部类的对象 / 类名。
  3. sizeof(外部类) = 外部类成员所占内存合计,和内部类没有任何关系。
class A
{
private:static int k;int h;
public:class B // B天生就是A的友元{public:void foo(const A& a){cout << k << endl;//OKcout << a.h << endl;//OK}};
};
int A::k = 1;
int main()
{A::B b;b.foo(A());return 0;
}

上述代码中,演示了这一系列特性,总的来说,B定义在A里面只是受A的类域限制,其他除了访问限定符影响类成员的访问之外,就和两个独立定义的类没什么区别了。当class B定义在private里时,就无法通过A::B bb;创建B类型的对象。

匿名对象

C++的匿名对象(也称为临时对象)是在代码中没有显式命名的对象。这种对象通常在创建后立即使用,并且在表达式结束时自动销毁(生命周期只存在于当前这一行)。匿名对象通常用于简化代码和提高可读性

class A
{
public:A(int a = 0):_a(a){cout << "A(int a)" << endl;}~A(){cout << "~A()" << endl;}
private:int _a;
};
class Solution {
public:int Sum_Solution(int n) {//...return n;}
};
int main()
{A aa1;// A aa1(); 不能这么定义对象,因为编译器无法识别下面是一个函数声明,还是对象定义// 我们可以这么定义匿名对象,匿名对象的特点是不用取名字,// 但是他的生命周期只有这一行,我们可以看到下一行他就会自动调用析构函数A();cout << endl;A aa2(2);// 匿名对象在这样场景下就很好用,当然还有一些其他使用场景,这个我们以后遇到了再说Solution().Sum_Solution(10);return 0;
}

以上代码中,给出了匿名对象的样例使用,作为匿名对象,其生命周期只存在于当前这一行当到下一行时就会被销毁,编译器自动调用其析构函数。虽然只有一行的生命周期,其还是有用武之地的。比如说像上面那样通过匿名对象直接调用类的成员函数,不需要我们单独再创建一个对象。

关于匿名对象的使用可以做一个总结:

1. 函数返回值:当函数返回一个对象时,如果该对象没有被赋值给任何变量,那么它就是一个匿名对象。

struct Foo {  Foo() { /* ... */ }  ~Foo() { /* ... */ }  
};  Foo createFoo() {  return Foo(); // 返回一个匿名对象  
}

2. 局部变量:在某些情况下,你可能希望创建一个局部变量但不为其命名。这通常发生在对象的生命周期非常短暂,且仅用于单个表达式时。

void doSomething() {  std::string("Hello, World!").size(); // 创建一个匿名std::string对象并获取其大小  
}

3. 直接初始化:在直接初始化中,你可以使用匿名对象来初始化另一个对象。

std::string str = std::string("Hello, World!"); // 使用匿名对象初始化str

注:由于匿名对象的生命周期很短,如果你在它们的生命周期之外访问它们,或者依赖于它们的特定销毁行为(例如,释放资源),那么可能会出现问题。因此,在使用匿名对象时,务必确保你了解其生命周期和销毁行为

结语

到这里本篇博客的内容基本上就结束了,类和对象到这里基本上算是基本掌握,算是迈过了C++的第一道坎。我们今天补充了类和对象的一些语法细节,包括static静态成员:没有this指针,所有对象共用;友元:包括友元函数和友元类;还提到了内部类:内部类天生是外部类的友元,但是外部类却不是内部类的友元;最后说到了匿名对象:声明周期只存在于当前一行。在下篇博客中,我们会提及C++内存管理相关的内容,敬请期待!

博主后续还会产出更多有意思的内容,感谢大家的支持!♥

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

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

相关文章

STM32的Flash读写保护

参考链接 STM32的Flash读写保护&#xff0c;SWD引脚锁的各种解决办法汇总&#xff08;2020-03-10&#xff09;-腾讯云开发者社区-腾讯云 (tencent.com)https://cloud.tencent.com/developer/article/1597959 STM32系列芯片Flash解除写保护的办法 - 知乎 (zhihu.com)https://zh…

调度问题变形的贪心算法分析与实现

调度问题变形的贪心算法分析与实现 一、问题背景与算法描述二、算法正确性证明三、算法实现与分析四、结论 一、问题背景与算法描述 带截止时间和惩罚的单位时间任务调度问题是一个典型的贪心算法应用场景。该问题的目标是最小化超过截止时间导致的惩罚总和。给定一组单位时间…

【AIGC调研系列】大型语言模型如何减少幻觉生成

在解读大型语言模型&#xff08;LLMs&#xff09;中的长格式事实性问题时&#xff0c;我们首先需要认识到这些模型在生成内容时可能会产生与既定事实不一致的情况&#xff0c;这种情况通常被称为“幻觉”[2][3]。这种现象不仅可能导致信息的误传&#xff0c;还可能对社会造成误…

使用nssm把批处理(.bat)文件设置为Windows 服务

本文以canal为例 使用nssm把批处理(.bat)文件设置为Windows 服务 下载 nssm&#xff1a; 前往 nssm 官方网站 下载适用于系统的 nssm 工具。 安装 nssm&#xff1a; 将下载的 nssm 压缩文件解压缩到一个合适的位置&#xff0c;如 D:\nlc\6.Canal-1.1.5\nssm-2.24\win64\nss…

深度学习运算:CUDA 编程简介

一、说明 如今&#xff0c;当我们谈论深度学习时&#xff0c;通常会将其实现与利用 GPU 来提高性能联系起来。GPU&#xff08;图形处理单元&#xff09;最初设计用于加速图像、2D 和 3D 图形的渲染。然而&#xff0c;由于它们能够执行许多并行操作&#xff0c;因此它们的实用性…

kafka启动报错(kafka.common.InconsistentClusterIdException)

文章目录 前言kafka启动报错(kafka.common.InconsistentClusterIdException)1. 查找日志2. 定位问题/解决 前言 如果您觉得有用的话&#xff0c;记得给博主点个赞&#xff0c;评论&#xff0c;收藏一键三连啊&#xff0c;写作不易啊^ _ ^。   而且听说点赞的人每天的运气都不…

SpringCloud系列(17)--将服务消费者Consumer注册进Zookeeper

前言&#xff1a;在上一章节中我们把服务提供者Provider注册进了Zookeeper&#xff0c;而本章节则是关于如何将服务消费者Consumer注册进Zookeeper 1、再次创建一个服务提供者模块&#xff0c;命名为consumerzk-order80 (1)在父工程下新建模块 (2)选择模块的项目类型为Maven并…

稳态视觉诱发电位 (SSVEP) 分类学习系列 (4) :Temporal-Spatial Transformer

稳态视觉诱发电位分类学习系列:Temporal-Spatial Transformer 0. 引言1. 主要贡献2. 提出的方法2.1 解码的主要步骤2.2 网络的主要结构 3. 结果和讨论3.1 在两个数据集下的分类效果3.2 与基线模型的比较3.3 消融实验3.4 t-SNE 可视化 4. 总结欢迎来稿 论文地址&#xff1a;http…

【进阶六】Python实现SDVRPTW(需求拆分)常见求解算法——禁忌搜索+模拟退火算法(TS+SA)

基于python语言&#xff0c;采用经典禁忌搜索&#xff08;TS&#xff09;模拟退火&#xff08;SA&#xff09;对 带硬时间窗的需求拆分车辆路径规划问题&#xff08;SDVRPTW&#xff09; 进行求解。 目录 往期优质资源1. 适用场景2. 代码调整2.1 需求拆分2.2 需求拆分后的服务时…

EureKa技术解析:科技行业的革新风暴(ai写作)

首先&#xff0c;这篇文章是基于笔尖AI写作进行文章创作的&#xff0c;喜欢的宝子&#xff0c;也可以去体验下&#xff0c;解放双手&#xff0c;上班直接摸鱼~ 按照惯例&#xff0c;先介绍下这款笔尖AI写作&#xff0c;宝子也可以直接下滑跳过看正文~ 笔尖Ai写作&#xff1a;…

如何驱动消费者自我裂变,助力平台引流与卖货双重提升

大家好&#xff0c;我是微三云周丽 在浩瀚的商业海洋中&#xff0c;电商行业一直以其独特的魅力和无限的可能性吸引着众多创业者和投资者的目光。近年来&#xff0c;一种被誉为电商模式中的“神盘”——众筹卖货模式&#xff0c;正悄然崭露头角&#xff0c;以其独特的运作方式…

Docker 入门篇(二)-- Linux 环境离线安装

引言 docker 系列文章&#xff1a; Docker 入门篇&#xff08;一&#xff09;-- 简介与安装教程&#xff08;Windows和Linux&#xff09; 一、安装环境准备 centos &#xff1a;CentOS Linux release 7.6.1810 (Core)docker 版本&#xff1a;docker-26.1.0.tgz 官网下载地址…

【RAG 论文】Chain-of-Note:为 RAG 引入 CoT 让模型生成阅读笔记来提高面对噪音文档和未知场景的鲁棒性

论文&#xff1a;Chain-of-Note: Enhancing Robustness in Retrieval-Augmented Language Models ⭐⭐⭐ Tencent AI Lab, arXiv:2311.09210 文章目录 一、论文速读二、实现的细节2.1 Note Design2.2 Data Collection2.3 Model Training 三、实验结果3.1 QA Performance3.2 对 …

虚拟机VMware下ROS Neotic(Ubuntu 20.04)下安装OpenCV

一、ROS安装 ROS的官方安装步骤&#xff1a; 1、noetic / Ubuntu 20.04 &#xff1a; http://wiki.ros.org/noetic/Installation/Ubuntu 2、melodic / Ubuntu 18.04&#xff1a; http://wiki.ros.org/melodic/Installation/Ubuntu 3、kinetic / Ubuntu 16.04&#xff1a; http:…

第三节课,后端登录【1】.2--本人

一、视频链接 网址&#xff1a; 后端用户脱敏和session-CSDN直播 二、代码开始 2.1 新建一个request参数。完成用户登录态键 快捷建&#xff0c; 全局变量 代码&#xff1a; // 3.记录用户的登录态/*** 这段代码是Java Web开发中的一部分&#xff0c;用于在会话&#xff08…

【目标检测】FPN特征金字塔完整流程详解

学习视频&#xff1a;1.1.2 FPN结构详解 对比 可以看到FPN是自上而下、自下而上并且可以进行多尺度特征融合的的层级结构。 具体结构 1x1 conv: 对通道数进行调整&#xff0c;不同大小的特征图通道数不同&#xff0c;越高层次的特征图通道数越大&#xff0c;论文中使用256个1…

ChatGPT/GLM API使用

模型幻觉问题 在自然语言处理领域&#xff0c;幻觉&#xff08;Hallucination&#xff09;被定义为生成的内容与提供的源内容无关或不忠实&#xff0c;具体而言&#xff0c;是一种虚假的感知&#xff0c;但在表面上却似乎是真实的。产生背景 检索增强生成&#xff08;RAG&…

线性神经网络示例

通过5个条件判定一件事情是否会发生&#xff0c;5个条件对这件事情是否发生的影响力不同&#xff0c;计算每个条件对这件事情发生的影响力多大&#xff0c;写一个线性神经网络模型pytorch程序,最后打印5个条件分别的影响力。 一 在这个场景中&#xff0c;一个线性神经网络&…

代码随想录算法训练营DAY32|C++贪心算法Part.2|122.买卖股票的最佳时机II、55.跳跃游戏、45.跳跃游戏II

文章目录 122.买卖股票的最佳时机II思路CPP代码 55.跳跃游戏思路CPP代码 45.跳跃游戏II思路方法一代码改善 CPP代码 122.买卖股票的最佳时机II 力扣题目链接 文章讲解&#xff1a;122.买卖股票的最佳时机II 视频讲解&#xff1a; 状态&#xff1a;本题可以用动态规划&#xff0…

boa交叉编译(移植到arm)

参考&#xff1a;CentOS7 boa服务器的搭建和配置-CSDN博客 以下操作在宿主机/编译平台操作&#xff1a; 1. 先执行[参考]1到3、 4.2、4.3、4.4、4.5 2. 修改MakeFile # 由以下&#xff1a; CC gcc CPP gcc -E # 改为&#xff1a; CC arm-linux-gnueabihf-gcc CPP arm-l…