【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;//OK
			cout << 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.mfbz.cn/a/578030.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

AWTK 开源串口屏开发(17) - 通过 MODBUS 访问数组数据

在 AWTK 串口屏中&#xff0c;内置了 MODBUS Client Channel 的模型&#xff0c;不用编写代码即可实现在 ListView 中显示数组数据。 MODBUS 协议一次只能读取 125 个 WORD&#xff0c;AWTK-MODBUS Client Channel 支持长数据&#xff0c;自动分成多个请求访问。 1. 功能 不用…

C语言入门课程学习记录5

C语言入门课程学习记录5 第23课 - C 语言中的常量第24课 - 初探程序中的数组第25课 - 数组特性深入剖析第26课 - 多维数组的概念与示例 本文学习自狄泰软件学院 唐佐林老师的 C语言入门课程&#xff0c;图片全部来源于课程PPT&#xff0c;仅用于个人学习记录 第23课 - C 语言中…

SecretFlow学习指南(2)学习路径

目录 一、模块架构 二、模块详解 三、算法协议 四、学习路线 一、模块架构 良好的分层设计可以提高开发效率和可维护性&#xff0c;满足不同用户的需求。隐语从上到下一共分为六层。 ●产品层&#xff1a;通过白屏化产品提供隐语整体隐私计算能力的输出&#xff0c;让用户简…

paddle ocr模型量化实践

参考&#xff1a;https://github.com/PaddlePaddle/PaddleOCR/blob/main/deploy/slim/quantization/README.md https://github.com/PaddlePaddle/PaddleOCR/blob/release/2.7.1/doc/doc_ch/FAQ.md 蒸馏 剪枝 量化 参考&#xff1a;https://blog.csdn.net/mddCSDN/article/de…

【MySQL】MySQL中MVCC多版本并发控制的概念

MySQL中MVCC多版本并发控制的概念 锁相关的知识我们已经学习完了&#xff0c;在其中我们提到过一个概念&#xff0c;那就是 MVCC 。这又是个什么东西呢&#xff1f;今天我们就来好好看看 MVCC 到底是干嘛的。 MVCC 多版本并发控制&#xff0c;它主要是控制 读 操作&#xff0c;…

x264 编码器源码分析综述

================================================================================ 系列文章 x264配置文章链接🔗Windows11编译x264源码https://blog.csdn.net/yanceyxin/article/details/135035650Mac调试x264源码https://blog.csdn.net/yanceyxin/article/details

《软件设计师教程:计算机网络浅了解计算机之间相互运运作的模式》

​ 个人主页&#xff1a;李仙桎 &#x1f525; 个人专栏: 《软件设计师》 ⛺️生活的理想&#xff0c;就是为了理想的生活! ​ ⛺️前言&#xff1a;各位铁汁们好啊&#xff01;&#xff01;&#xff01;&#xff0c;今天开始继续学习中级软件设计师考试相关的内容&#xff0…

python中怎么注释多行

多行代码注释 方法一&#xff1a;先选中要注释的段落&#xff0c;然后按下“ctrl/”&#xff0c;即可实现多行代码的注释。效果如下&#xff1a; 再一次按下“ctrl/”就可以取消注释。 方法二&#xff1a;跟注释单行一样在每一行前面输入“shift#”。 #r(i-arr[idx])*rat[idx]…

三阶魔方公式大全 图解

https://www.mitao521.com/miji/2020112215034.html 三阶魔方七步还原法的公式有R’UF’U’、R’D’RD X,3OR5,R U R’,(RU R’U’),(RU R’U’)3,U’ L’ U L U F U’ F’,U R U’ R’ U’ F’ U F,F(R U R’ U’)F’。 还有(R U R’ U’)2和(R U R’ U’)5,R2 D2 R’ U’ R …

各种螺纹介绍

按用途&#xff0c;有三个主要大类&#xff1a; 第一&#xff0c;连接螺纹&#xff0c;用于紧固&#xff0c;即是螺栓螺母&#xff1b; 第二&#xff0c;传动螺纹&#xff0c;就是车床走刀那种&#xff1b; 第三&#xff0c;管螺纹&#xff0c;管道连接用。 按标准&#xf…

【刷题篇】动态规划-01背包问题(十)

文章目录 1、01背包2、分割等和子集3、目标和4、最后一块石头的重量 II 1、01背包 #include <iostream> #include<vector> using namespace std;int main() {int n,v;cin>>n>>v;vector<int> Weight(n1);vector<int> Value(n1);vector<i…

PDF加密了无法编辑?解密方法来了!

一下午都在捣鼓各种格式问题&#xff0c;首先是需要合并几个 PDF&#xff0c;然而有一个文件加密了无法操作&#xff0c;碰到加密不能编辑就很头痛&#xff0c;终于让我找到一个可行的方法了&#xff0c; 首先就这个加密文件右键选择打开方式-Google Chrome>>打开>>…

环形链表——java

给你一个链表的头节点 head &#xff0c;判断链表中是否有环。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统内部使用整数 pos 来表示链表尾连接到链表中的位置&#xff08;…

2024年Q1季度洗衣机行业线上市场销售数据分析

Q1季度洗衣机线上市场表现不如预期。 根据鲸参谋数据显示&#xff0c;2024年1月至3月线上电商平台&#xff08;京东天猫淘宝&#xff09;洗衣机累计销量约650万件&#xff0c;环比下降14%&#xff0c;同比下降14%&#xff1b;累计销售额约96亿元&#xff0c;环比下降30%&#…

军工单位安全内网文件导出,怎样做到严密的安全管控?

军工单位是指承担国家下达的军事装备、产品研制、生产计划任务的企、事业单位&#xff0c;主要包括电子工业部、航空工业总公司、航天工业总公司、兵器工业总公司、核工业总公司、船舶工业总公司、中国工程物理研究院及各省国防工业办公室等。 军工单位的特点主要体现在以下几个…

(学习日记)2024.04.20:UCOSIII第四十八节:各文件功能概览

写在前面&#xff1a; 由于时间的不足与学习的碎片化&#xff0c;写博客变得有些奢侈。 但是对于记录学习&#xff08;忘了以后能快速复习&#xff09;的渴望一天天变得强烈。 既然如此 不如以天为单位&#xff0c;以时间为顺序&#xff0c;仅仅将博客当做一个知识学习的目录&a…

和鲸科技出席第五届空间数据智能学术会议,执行总裁殷自强受邀发表主题报告

4月26日&#xff0c;由 ACM SIGSPATIAL 中国分会、ACM SIGMOD 中国分会主办的第五届空间数据智能学术会议&#xff08;SpatialDI 2024&#xff0c;下简称“会议”&#xff09;在南京盛大开幕。本次会议特邀李清泉院士、周成虎院士、丛高教授、谢炯博士、张雪英教授等国内外知名…

Matlab|交直流混合配电网潮流计算(统一求解法)

目录 1 主要内容 算例模型 统一求解法迭代方程 算法流程图 2 部分代码 3 程序结果 4 下载链接 1 主要内容 该程序为matlab代码&#xff0c;采用统一求解法对交直流混合配电网进行潮流计算&#xff0c;统一迭代法又称统一求解法&#xff0c;其思路是将混联系统中的交流网…

基于springboot实现中药实验管理系统设计项目【项目源码+论文说明】计算机毕业设计

基于springboot实现中药实验管理系统设计演示 摘要 随着信息技术在管理上越来越深入而广泛的应用&#xff0c;管理信息系统的实施在技术上已逐步成熟。本文介绍了中药实验管理系统的开发全过程。通过分析中药实验管理系统管理的不足&#xff0c;创建了一个计算机管理中药实验管…

LMDeploy量化部署LLMVLM实践-笔记五

本次课程由西北工业大学博士生、书生浦源挑战赛冠军队伍队长、第一期书生浦语大模型实战营优秀学员【安泓郡】讲解【OpenCompass 大模型评测实战】课程 课程视频&#xff1a;https://www.bilibili.com/video/BV1tr421x75B/ 课程文档&#xff1a;https://github.com/InternLM/…
最新文章