C++ | 类和对象(下)(static成员、友元、内部类、匿名对象)

news2024/9/21 4:15:15

目录

​编辑

static成员

static性质简介

static属于整个类,属于所有对象

static成员的声明与定义

static函数

友元friend

友元特性简介

友元关系讲解

内部类

特性一

特性二

匿名对象

结语


static成员

static性质简介

static成员在类里面是非常独特的,因为这个成员并不存在于类里面,就像是函数一样

我们先来看这么一段程序:

class A
{
public:
	int _a;
	static int _b;
};

int main()
{
	A aa1;
	cout << sizeof(aa1) << endl;
	return 0;
}

我们能看到,这段程序的目的就是看这个类的大小,我们的类里面有一个普通的int成员和一个static成员,但是结果为 4,这说明static成员是不存在于类中的

static属于整个类,属于所有对象

这句话的意思就是,我们无论创建了多少个对象,所有的对象想要用这个static成员,那么使用的就都是同一个static成员,因为这个static成员属于所有对象

我们可以验证一下这个特性,来看这么一段代码:

ps:该段代码中有关于static成员声明与定义的问题和static成员函数的问题,稍后会讲到

class A
{
public:
	A()
	{
		_b++;
	}

	~A()
	{
		_b--;
	}

    //静态成员函数
	static int get_b()
	{
		return _b;
	}

private:
	int _a;
	static int _b;//声明
};

int A::_b = 0;//定义

int main()
{
	A aa1;
	A aa2;
	A aa3;
	A aa4;
	cout << A::get_b() << endl;
	return 0;
}

我们能看到,每个对象创建出来时,都会调用对应的构造函数,而我们在构造函数里面就干一件事:将静态成员++

又因为所有对象共用同一个static成员,所以我们每创建一个对象,我们的_b就会++一下

最后,我们再通过静态成员函数将静态成员变量取出,就能看到具体此时有几个对象还存在了

static成员的声明与定义

因为是static成员,所以是不能在构造函数中进行初始化的

那我们可以按如下方式赋值吗?

private:
	int _a = 0;
	static int _b = 0;

答案是否定的,因为这里的值是给初始化列表看的,但是我们的static成员都不在类里面,所以这种方法是行不通的

而静态成员的其中一个特性就是——静态成员变量必须在类外面初始化

而类中的只是声明,而类外面的是定义,定义时不加关键字static,但是需要指定类域,如下:

class A
{
private:
	int _a;
	static int _b;
};

int A::_b = 0;

static函数

如果我们将static成员定义为私有,那我们就无法在类外面使用该成员

由此,C++里就搞出了一个static函数,如下:

class A
{
public:

	static int get_b()
	{
		return _b;
	}

private:
	int _a;
	static int _b;
};

int A::_b = 0;

如上,我们写了一个函数get_b,通过将这个函数设为公有我们就能取到_b

并且由于这个函数是static函数,所以没有this指针,也就无法访问到除了静态成员以外的其他成员

友元friend

友元特性简介

当一个类A有特殊情况,必须要访问类B中的私有成员时,我们就可以使用友元

如下:

class A
{
	friend class B;
	int _a = 1;
};

class B
{
public:
	int getnum()
	{
		return _t._a;
	}
private:
	A _t;
};

int main()
{
	B b1;
	cout << b1.getnum() << endl;
	return 0;
}

我们能看到,类A中的_a是私有的,这就意味着其他类是无法使用的,但是我们可以将类B设置为类A的友元,这样子我们的类B就能访问到类A的私有成员了

添加友元的方式就是在类的声明前面加一个friend

当然还有函数的友元,如下:

class Date
{
	friend ostream& operator<<(ostream& _cout, const Date& d);
	friend istream& operator>>(istream& _cin, Date& d);
public:
	Date(int year = 1900, int month = 1, int day = 1)
		: _year(year)
		, _month(month)
		, _day(day)
	{}
private:
	int _year;
	int _month;
	int _day;
};
ostream& operator<<(ostream& _cout, const Date& d)
{
	_cout << d._year << "-" << d._month << "-" << d._day;
	return _cout;
}
istream& operator>>(istream& _cin, Date& d)
{
	_cin >> d._year;
	_cin >> d._month;
	_cin >> d._day;
	return _cin;
}

如上是我们在上文中讲到的Date类(日期类),如若有不了解的,可以点下面链接复习一下:

Date 日期类的实现

和友元类差不多,都是声明前面加一个friend

友元关系讲解

这里关系到一个问题,我们可以联系现实:

我喜欢你,你就一定得喜欢我吗?

我把你当朋友,你就一定得把我当朋友吗?

我是你爸的朋友,我就一定得是你的朋友吗?

这几句话就讲解了:友元关系不是相互的,我把你当朋友,你可以用我的东西,但是我不一定能用你的东西,除非你把我当成朋友

同时,友元关系是不能继承的,这个知识点了解就好,这关系到以后会讲的继承章节的相关内容

内部类

内部类相对来说比较简单

我们在一个类里面,能定义一个int变量,能定义一个static变量,同样的,我们也可以定义一个类类型的变量,也就是在类里面定义一个类

特性一

class A
{
	int _a = 0;
	static int _s;

	class B // 内部类
	{
		int _k;

		void getAnum(const A& a)
		{
			cout << _s << endl;
			cout << a._a << endl;
		}
	};

};
int A::_s = 0;

如上,我们可以总结出内部类的其中一个特性:

内部类天生就是外部类的友元,即内部是外部的朋友,所以内部类可以使用外部类的私有

但是外部类不是内部类的友元,所以外部类不能使用内部类的私有

也就是:不是我把你当朋友,你就一定得把我当朋友

特性二

我们再来看这么一段代码:

class A
{
	int _a = 0;
	static int _s;

	class B // 内部类
	{
		int _k;

		void getAnum(const A& a)
		{
			cout << _s << endl;
			cout << a._a << endl;
		}
	};

};
int A::_s = 0;

int main()
{
	A a1;
	cout << sizeof(a1) << endl;
	return 0;
}

我们可以看到,对类A的大小进行统计以后发现,类B是不计在类A里面的

由此我们可以得出第二个特性:

内部类和外部类是两个平行的类,内部类唯一的特殊点就是受到类域的限制和天生友元关系

也就是说,这两个类之间并没有说谁大谁小,都是两个一样的类,只不过需要访问内部类的话就需要对类域进行限制,如下:

A a1;
A::B _b;

匿名对象

我们来看这么一个例子(假设有一个类A已存在):

A a1; //有名对象
A(); //匿名对象

匿名对象和有名对象的区别在于:有名对象的生命周期是当前域结束时才到

但是匿名对象的生命周期是他所在的那一行,也就是即用即销毁

我们来看下面这一段代码:

class A
{
public:
	A()
	{
		cout << "A()" << endl;
	}
	~A()
	{
		cout << "~A()" << endl;
	}
};

int main()
{
	A a1;
	A();
	A a2;
	return 0;
}

我们可以明显看到,匿名对象那里是刚声明完就销毁了,而有名对象是直到程序结束了才销毁

至于匿名对象的好处,就是调用起来会更省事

现在看起来可能会觉得没什么用,但是当我们在学习STL相关知识的时候就能体会到真香定律(bushi

举个栗子:

#include<map>

int main()
{
	map<int, int> m1;

	//使用有名对象的插入方式
	pair< int, int> s1(1, 2);
	m1.insert(s1);

    //使用匿名对象的插入方式
    m1.insert(pair<int, int>(1, 2));

	//使用隐式类型转换为匿名对象的插入方式
	m1.insert({ 1,2 });

	return 0;
}

map是stl中的一个数据结构,而我们每次插入数据都需要插入一个pair类型的数据进去

如果是有名对象的话,我们就需要将pair类型的变量定义出来再插入进去(s1)

但如果是匿名对象的话,我们直接在插入里面定义一个匿名对象,即用即销毁也无所谓,反正数据插入进去了

当然还有更好的方法,就是走隐式类型转换,当然这些显然有点超纲,我们只需要知道匿名在未来的学习中非常常见即可

结语

距离上一篇更新已经过去了三个月整了,这三个月一直忙于C++和算法,现在也算是抽出时间来补一补博客了,突然有种高中知识学完了但发现初中的作业还没写完的感觉(苦笑)

如果感觉这篇博客对各位有帮助的话,希望可以多多支持喔!!!

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

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

相关文章

ContentProvider的相关知识总结

1.ContentProvider概念讲解&#xff1a; 2.使用系统提供的ContentProvider 其实很多时候我们用到ContentProvider并不是自己暴露自己的数据&#xff0c;更多的时候通过 ContentResolver来读取其他应用的信息&#xff0c;最常用的莫过于读取系统APP&#xff0c;信息&#xff0c…

Kubernetes中的CRI、CNI与CSI:深入理解云原生存储、网络与容器运行时

引言 随着云原生技术的飞速发展&#xff0c;Kubernetes&#xff08;简称K8s&#xff09;作为云原生应用的核心调度平台&#xff0c;其重要性日益凸显。K8s通过开放一系列接口&#xff0c;实现了高度的可扩展性和灵活性&#xff0c;其中CRI&#xff08;Container Runtime Inter…

使用归一化连接计数的胸部CT成像:预测CanCOLD研究中的肺气肿进展| 文献速递-AI辅助的放射影像疾病诊断

Title 题目 CT Chest Imaging Using Normalized Join-Count: Predicting Emphysema Progression in the CanCOLD Study 使用归一化连接计数的胸部CT成像&#xff1a;预测CanCOLD研究中的肺气肿进展 Background 背景 Pre-existing emphysema is recognized as an indicator…

【C++】------继承(一)

目录 前言 一、概念与定义 Ⅰ、是什么&#xff1f; Ⅱ、定义 1.定义格式&#xff1a; 2.继承方式和访问限定符 3.基类&#xff08;父类&#xff09;成员访问方式的变化 二、父类与子类的赋值转化 基本认识 原理 三、 继承中的作用域 四、子类(派生类)的默认成员函…

Spring中是如何实现IoC和DI的?

前言&#xff1a;在前一篇文章中对于IoC的核心思想进行了讲解&#xff0c;而本篇文章则从Spring的角度入手&#xff0c;体会Spring对于IoC是如何实现的。 如果对IoC还有不太了解的可以阅读上一篇文章&#xff0c;相信一定会带来全新的收获&#xff1a;什么是IoC&#xff08;控制…

5.5软件工程-系统测试

系统测试 意义和目的原则测试过程测试策略测试方法练习题 测试用例设计黑盒测试等价类划分边界值分析错误推测因果图 白盒测试逻辑覆盖循环覆盖基本路径测试法 练习题 调试软件度量练习题 考点少&#xff0c;知识点多 意义和目的 系统测试的意义&#xff1a;系统测试是为了发现…

浅谈Redis集群架构与主从架构

目录 1. Redis集群1.1 集群概念1.2 集群分片1.3 重新分片 2. 集群的主从模型2.1 主从模型2.2 主节点选举 1. Redis集群 1.1 集群概念 面试官&#xff1a;我看你简历写了Redis集群&#xff0c;你说一说&#xff1f; Redis主从架构和Redis集群架构是两种不同的概念&#xff0c;大…

【Spring成神之路】从源码角度深度刨析Spring循环依赖

文章目录 一、引言二、循环依赖出现的场景2.1 有参构造导致的循环依赖问题2.2 属性注入出现的依赖问题2.3 Spring IOC创建Bean的流程2.4 有参构造为何失败2.5 属性注入为何能成功2.6 AOP导致的循环依赖 三、Spring循环依赖源码刨析四、Spring循环依赖案例刨析 一、引言 循环依…

【MATLAB源码】数学建模基础教程---初步认识数学建模

系列文章目录在最后面&#xff0c;各位同仁感兴趣可以看看&#xff01; 什么是数学建模 含义1.区分数学模型和数学建模2. 建立数学模型的注意事项3.数学建模流程图解4.数学建模模型分类5.论文常用套路6.最后&#xff1a;总结系列文章目录 含义 所谓数学建模&#xff0c;简言…

Python 中实现聊天客户端库

在 Python 中实现一个简单的聊天客户端库可以通过使用 socket 模块来处理网络通信。我们可以构建一个基于 TCP 的简单聊天系统&#xff0c;其中包括一个服务器和一个客户端。 1、问题背景 假设您正在尝试编写一个 Python 库&#xff0c;用于实现某个聊天协议的客户端。在连接…

c++入门基础(下篇)————引用、inline、nullptr

引用 引用的概念和定义 引⽤不是新定义⼀个变量&#xff0c;⽽是给已存在变量取了⼀个别名&#xff0c;编译器不会为引⽤变量开辟内存空间&#xff0c; 它和它引⽤的变量共⽤同⼀块内存空间。 类型& 引用别名 引用对象; 就像孙悟空也叫齐天大圣 猪八戒也叫天蓬元帅。…

正点原子imx6ull-mini-Linux驱动之Linux 自带的 LED 灯驱动实验(16)

前面我们都是自己编写 LED 灯驱动&#xff0c;其实像 LED 灯这样非常基础的设备驱动&#xff0c;Linux 内 核已经集成了。Linux 内核的 LED 灯驱动采用 platform 框架&#xff0c;因此我们只需要按照要求在设备 树文件中添加相应的 LED 节点即可&#xff0c;本章我们就来学习如…

Level3答案

突然发现&#xff0c;忘记公布了Level3答案&#xff1a; 1、 (1)heker.h HeiKe.h (2)Make_Text() (3)3 (4)heker.h 2、 (1)ArtText.h Maker_World.h (Maker_Game头文件组) (2)5.0 附加题、 我把标题截了张图&#xff01; 这是我们 Cookie Maker工作室 新出来的 “无标题技术”…

JavaScript基础——JavaScript数据及数据类型

JavaScript中数据的分类 数据是指设备、浏览器可以识别的内容。在JavaScript中&#xff0c;数据可分为基本数据类型&#xff08;值数据类型&#xff09;和引用数据类型。 console.log()函数 浏览器中按下F12或者右击检查&#xff0c;可以打开控制台。 在JavaScript中&#xff0…

微服务通过X-Forwarded-For获取客户端最原始的IP地址

文章目录 引言I 通过转发IP列表获取用户的IP地址II 存储真实IP字段到MDC中2.1 自己存储真实IP字段,方便获取。2.2 feign 传递MDC数据(将MDC中数据传入header)III 处理真实IP(应用)3.1 从MDC获取存储到日志系统中3.2 logback获取MDC数据(IP、追踪码)3.3 打印接口的请求IP引…

教你用python代码写一个中国象棋游戏

编写一个完整的中国象棋游戏是一个复杂的项目&#xff0c;因为它涉及到图形用户界面(GUI)的设计、游戏规则的实现、AI对手的开发等多个方面。不过&#xff0c;我可以提供一个简化的框架和一些基本思路&#xff0c;帮助你开始这个项目。 由于这里不能完整地实现一个图形化的象棋…

三十六、MyBatis-Plus(2)

&#x1f33b;&#x1f33b; 目录 一、CRUD 扩展&#xff08;1)1.1 Insert1.2 主键生成策略1.2.1 源码解释1.2.2 Twitter的snowflake算法 (雪花算法)1.2.3 主键自增&#xff1a;AUTO 我们需要配置主键自增1.2.4 手动输入&#xff1a;INPUT 就需要自己写 id 1.3 Update1.4 自动填…

2024杭电多校第五场

第一题&#xff1a;开关灯 直接暴力找规律。 发现如果n2&#xff08;mod3&#xff09;那么就是2的n-1次方。否则直接是2的n次方。 暴力代码 #include<bits/stdc.h> using namespace std; #define int long longsigned main() {int temp[100];temp[0] 1;for (int i …

SOMEIP_ETS_001:数组长度超过消息长度允许的范围

测试目的&#xff1a; 验证DUT&#xff08;Device Under Test&#xff0c;被测设备&#xff09;在接收到数组长度超过SOME/IP协议允许的最大长度时&#xff0c;是否能够返回错误消息。 描述 本测试用例旨在检查DUT在接收到一个SOME/IP消息时&#xff0c;如果该消息中的数组长…

Java学习:今日成果,明日挑战

阅读指南&#xff1a;[题目] - 精选摘要 题目1.面向对象编程意味着2.以下哪项不是 Java 关键字&#xff1f;3.基础数据类型在堆栈上分配&#xff1f;4.以下代码将导致&#xff1a;5.以下输出是什么 &#xff1f;6.如果我们声明&#xff1a;7.Java 使用按值调用。 以下方法调用传…