C++ 类和对象(友元、内部类、匿名对像)

news/2025/2/24 9:04:40

目录

一、前言

二、正文

1.友元

1.1友元函数的使用

1.1.1外部友元函数可访问类的私有成员,友员函数仅仅是一种声明,他不是类的成员函数。

1.1.2一个函数可以是多个类的友元函数

2.友元类的使用

2.1什么是友元类

2.2 友元类的关系是单向的,不具有交换性。

2.3 友元类关系不能传递。

3.内部类

3.1内部类的使用

3.1.1 由于内部类是一个独立的类,跟定义在全局相比,它只是受外部类类域限制和访问限定符限制,所以外部定义的对象不包含内部类。

3.1.2内部类默认是外部类的友元类

4.匿名对象

4.1匿名对象的应用场景


一、前言

昨天我们已经分享了类和对象中类型转换和static成员的知识,有兴趣的小伙伴可以看一下:

https://blog.csdn.net/yiqingaa/article/details/144066165

今天让我们在一起学习类和对象中的友元、内部类,和匿名对象吧。

二、正文

1.友元

  • 友元提供了一种突破类访问限定符封装的方式,友元分为:友元函数和友元类,在函数声明或者类声明的前面加friend,并且把友元声明放到一个类的里面。
  • 外部友元函数可访问类的私有和保护成员,友元函数仅仅是一种声明,他不是类的成员函数。
  • 友元函数可以在类定义的任何地方声明,不受类访问限定符限制。
  • 一个函数可以是多个类的友元函数。
  • 友元类中的成员函数都可以是另一个类的友元函数,都可以访问另一个类中的私有和保护成员。
  • 友元类的关系是单向的,不具有交换性,比如A类是B类的友元,但是B类不是A类的友元。
  • 友元类关系不能传递,如果A是B的友元,B是C的友元,但是A不是C的友元。
  • 有时提供了便利。但是友元会增加耦合度,破坏了封装,所以友元不宜多用。 

1.1友元函数的使用

 从上图可以看出在我们的Print函数中系统爆出了警告,说A::_a1、A::_a2是不可访问的。那是因为_a1、_a2被限定符private给限制住了,在类外面无法访问类里面的私有成员(这里是_a1和_a2)那么我们如何在类外面定义的函数访问我们的私有成员呢?这里我们就可以借助我们的友元函数来解决这个问题:

#include<iostream>
using namespace std;
class A
{
public:
	friend void Print(const A& aa);//我们只需要把函数抄写一下放在类里面,然后前面加个friend就行。
	A(int a1 = 1, int a2 = 2)
	{
		_a1 = a1;
		_a2 = a2;
	}
private:
	int _a1;
	int _a2;
};
void Print(const A& aa)
{
	cout << aa._a1 << " " << aa._a2 << endl;
}
int main()
{
	A a;
	Print(a);
	return 0;
}

友元函数的使用方法很简单,只需要把定义在类外面的函数抄写一份到类里面,然后在函数前面加个friend就行了,friend+函数->友元函数(前提是这个函数定义在类外面,不然这么做其实无实际意义,毕竟如果这个函数是定义在类里面的,直接就可以调用私有成员。没必要多此一举)

  • 友员函数可以这么理解:之前我们是陌生人,我去你家里玩,私闯民宅这是违法的。不过现在我们是朋友了(我是你的友元函数,如上图中Print是类A的友元函数,即Print是A的朋友)那么我去你家玩,就没有任何问题了。
  • 友元可以定义在类里面的任何地方,哪怕是定义在限制符private里面都没问题,不过个人建议放在类里面的第一行,易于让人知道:哦,你使用了友元函数(清晰明了)。

  • 1.1.1外部友元函数可访问类的私有成员,友员函数仅仅是一种声明,他不是类的成员函数。

如图所示,当我们想要通过  类名+::的方式去访问类中的公共成员的时候,只发现了类A的构造函数,而没有发现Print,这说明了友员函数仅仅只是一种声明,而非是这个类的成员函数。

  • 1.1.2一个函数可以是多个类的友元函数
#include<iostream>
using namespace std;
class B;
class A
{
public:
	friend void Print(const A& aa,const B& bb);//Print是A的盆友
	A(int a1 = 1, int a2 = 2)
	{
		_a1 = a1;
		_a2 = a2;
	}
private:
	int _a1;
	int _a2;
};
class B
{
public:
	friend void Print(const A& aa, const B& bb);//Print是B的盆友
	B(int b1 = 3, int b2 = 4)
	{
		_b1 = b1;
		_b2 = b2;
	}
private:
	int _b1;
	int _b2;
};
void Print(const A& aa,const B& bb)
{
	cout << aa._a1 << " " << aa._a2 << endl;
	cout << bb._b1 << " " << bb._b2 << endl;
}
int main()
{
	A a;
	B b;
	Print(a,b);
	return 0;
}

由上图可知,函数Print不仅是类A的盆友,同时也是类B的盆友。就像一个人可以是很多人的盆友一样,并不是独属于你的盆友。

2.友元类的使用

  • 2.1什么是友元类

定义:一个类可以将另一个类声明为它的友元类,被声明为友元的类将获得对原始类所有成员的访问权限,无论是私有、保护还是公有成员  。

#include<iostream>
using namespace std;
class B;
class A
{
public:
	friend class B;//这里我们直接让B整个类都是A的盆友,这样我们不仅在Fun1函数中能使用A中隐私变量,在Func2中也能使用A中隐私成员。
	A(int a1 = 1, int a2 = 2)
	{
		_a1 = a1;
		_a2 = a2;
	}
	void Func1()
			{
				cout<< _a1 << " " << _a2 << endl;
			}
private:
	int _a1;
	int _a2;
};
class B
{
public:
	B(int b1 = 3, int b2 = 4)
	{
		_b1 = b1;
		_b2 = b2;
	}
	void Func2(const A& aa)
	{
		cout << aa._a1 << " " << aa._a2 << endl;
	}
	void Func3(const A& aa)
	{
		cout << aa._a1 << " " << aa._a2 << endl;
	}
private:
	int _b1;
	int _b2;
};
int main()
{
	A a;
	B b;
	b.Func2(a);
	b.Func3(a);
	return 0;
}

就例如上图所示,如果我们想在B类中任意使用A中的私有成员(_a1和_a2)我们可以让B一整个类都成为类A的友元,这样我们不仅让类B中的Func1能访问到A中的私有成员(_a1和_a2),Func2中也能访问到A中的私有成员(_a1和_a2)。

  • 2.2 友元类的关系是单向的,不具有交换性。

比如A类是B类的友元,但是B类不是A类的友元,我们如果想要在A类中访问B中私有成员(_b1和_b2)就访问不到。

  • 2.3 友元类关系不能传递。

如果A是B的友元,B是C的友元,但是A不是C的友元。

可以理解为我是你的盆友,你是他的盆友,但这并不意味着,我和他就是盆友。

3.内部类

  • 如果一个类定义在另一个类的内部,这个内部类就叫做内部类。内部类是一个独立的类,跟定义在全局相比,他只是受外部类类域限制和访问限定符限制,所以外部类定义的对象中不包含内部类。
  • 内部类默认是外部类的友元类。
  • 内部类本质也是一种封装,当A类跟B类紧密关联,A类实现出来主要就是给B类使用,那么可以考虑把A类设计为B的内部类,如果放到private/protected位置,那么A类就是B类的专属内部类,其他地方都用不了。 
3.1内部类的使用

#include<iostream>
using namespace std;
class A
{
public:
	A(int a1 = 1, int a2 = 2)
	{
		_a1 = a1;
		_a2 = a2;
	}
	void Func1()const
	{
		cout<< _a1 << " " << _a2 << endl;
	}
	class B
	{
	public:
		B(int b1 = 3, int b2 = 4)
		{
			_b1 = b1;
			_b2 = b2;
		}
		void Func2(const A&aa)
		{
			cout <<aa. _a1 << " " << aa._a2 << endl;
		}
			void Func3(const A& aa)
	{
		cout << aa._a1 << " " << aa._a2 << endl;
	}
	private:
		int _b1;
		int _b2;
	};
private:
	int _a1;
	int _a2;
};
class B
{
public:
	B(int b1 = 3, int b2 = 4)
	{
		_b1 = b1;
		_b2 = b2;
	}
private:
	int _b1;
	int _b2;
};
int main()
{
	A a;
	return 0;
}

上面就是我们简单的写了个内部类。类B被定义在类A的内部。

  • 3.1.1 由于内部类是一个独立的类,跟定义在全局相比,它只是受外部类类域限制和访问限定符限制,所以外部定义的对象不包含内部类。

看图可知,外部定义的对象a中没有类B,只有成员函数Fun1。

  • 3.1.2内部类默认是外部类的友元类

因为B被定义在A中,所以B是A的盆友,即在B中可以任意访问到A中的私有成员。

例如:B中的Func2和Func1都能访问到A的私有成员(_a1和_a2)。

4.匿名对象

  • 用类型(实参)定义出来的对象叫做匿名对象,相比之前我们定义的 类型 对象名(实参) 定义出来的叫有名对象。
  • 匿名对象生命周期只在当前一行,一般临时定义一个对象当前用一下即可,就可以定义匿名对象。 

如上图所示,就是有名对象和匿名对象的区别。

值得注意的是:匿名对象的生命周期,只有该匿名对象创建的哪一行,一旦运行到下一行,该匿名对象就被销毁了。

4.1匿名对象的应用场景

匿名对象的使用主要是方便。例如:

我们只是想调用一下成员函数Func1:

  1. 创造有名对象a,再通过实例化对象a访问Func1,需要两行代码。如上图标号1。
  2. 直接创造匿名对象,直接访问Func1,只需要一行代码。如上图标号。

现在知道匿名对象的作用了吗,其实就是为了图方便,能写一行代码完成的事情,为什么要写两行呢,对吧。

三结言

本次博客的分享就到这呢,同学们咱们下次再见,拜拜喽。


http://www.niftyadmin.cn/n/5864145.html

相关文章

Distilabel 入门指南:基本概念、安装与快速上手

系列文章&#xff1a; Distilabel 入门指南&#xff1a;基本概念、安装与快速上手 Distilabel 基础指南&#xff1a;概念与入门 Distilabel 高级指南&#xff1a;深度功能与最佳实践 Distilabel API 文档&#xff1a;功能详解与使用 正文&#xff1a; 概述 Distilabel 是…

掌握 ElasticSearch 组合查询:Bool Query 详解与实践

掌握 ElasticSearch 组合查询&#xff1a;Bool Query 详解与实践 一、引言 (Introduction)二、Bool 查询基础2.1 什么是 Bool 查询&#xff1f;2.2 Bool 查询的四种子句2.3 语法结构 三、Bool 查询的四种子句详解与示例3.1 must 子句3.2 filter 子句3.3 should 子句3.4 must_no…

QQ登录测试用例报告

QQ登录测试用例思维导图 一、安全性测试用例 1. 加密传输与存储验证 测试场景&#xff1a;输入账号密码并提交登录请求。预期结果&#xff1a;账号密码通过加密传输&#xff08;如HTTPS&#xff09;与存储&#xff08;如哈希加盐&#xff09;&#xff0c;无明文暴露。 2. 二…

【springcloud】快速搭建一套分布式服务springcloudalibaba(一)

第一篇 基于nacos搭建一套springcloud分布式服务 项目所需 maven nacos java8 idea git 当前项目为快速搭建 用户服务提供查询&#xff0c;商品服务查询用户信息 请先准备好环境&#xff0c;可以直接clone下来项目去部署。 快速搭建一套分布式服务 项目结构关于搭建下载配置…

驱动开发系列39 - Linux Graphics 3D 绘制流程(二)- 设置渲染管线

一:概述 Intel 的 Iris 驱动是 Mesa 中的 Gallium 驱动,主要用于 Intel Gen8+ GPU(Broadwell 及更新架构)。它负责与 i915 内核 DRM 驱动交互,并通过 Vulkan(ANV)、OpenGL(Iris Gallium)、或 OpenCL(Clover)来提供 3D 加速。在 Iris 驱动中,GPU Pipeline 设置 涉及…

跨平台公式兼容性大模型提示词模板(飞书 + CSDN + Microsoft Word)

飞书云文档 CSDN MD编辑器 Microsoft Word 跨平台公式兼容方案&#xff1a; 一、背景痛点与解决方案 在技术文档创作中&#xff0c;数学公式的跨平台渲染一直存在三大痛点&#xff1a; 飞书云文档&#xff1a;原生KaTeX渲染与导出功能存在语法限制微软Word&#xff1a;Math…

数据结构3-栈和队列

栈和队列的操作特点 栈和队列是限定插入和删除只能在表的“端点”进行的线性表 栈&#xff08;操作尾部&#xff09;和队列&#xff08;操作头部&#xff09;是线性表的子集&#xff08;是插入和删除位置受限的线性表&#xff09; 栈&#xff08;Stack&#xff09; 栈是一个…

机器人部分专业课

华东理工 人工智能与机器人导论 Introduction of Artificial Intelligence and Robots 必修 考查 0.5 8 8 0 1 16477012 程序设计基础 The Fundamentals of Programming 必修 考试 3 64 32 32 1 47450012 算法与数据结构 Algorithm and Data Structure 必修 考试 3 56 40 …