当前位置: 首页 > news >正文

33.友元

        类的主要特点之一是数据隐藏,即类的私有成员无法在类的外部(作用域之外)访问。但是,有时候需要在类的外部访问类的私有成员,怎么办?

        解决方法是使用友元函数,友元函数是一种特权函数,c++允许这个特权函数访问私有成员。这一点从现实生活中也可以很好的理解:

        比如你的家,有客厅,有你的卧室,那么你的客厅是Public的,所有来的客人都可以进去,但是你的卧室是私有的,也就是说只有你能进去,但是呢,你也可以允许你的闺蜜好基友进去。

        程序员可以把一个全局函数、某个类中的成员函数、甚至整个类声明为友元。

1. 全局函数作友元函数

        友元函数的目的:访问类中的私有成员属性

#include<iostream>
#include<string>
using namespace std;

class Building {

	//让全局函数:好朋友函数  变成友元函数
	friend void goodfriend(Building* building);

public:
	string m_room;    //客厅

	Building()
	{
		this->m_Bedroom = "卧室";
		this->m_room = "客厅";
	}
private:
	string m_Bedroom; //卧室
};


//全局函数   好朋友
void goodfriend(Building * building) {
	cout << "好朋友正在参观" << building->m_room << endl;
	cout << "好朋友正在参观" << building-> m_Bedroom << endl;
}

void test()
{
	Building* building = new Building;
	goodfriend(building);
}
int main()
{
	test();
}

运行结果:

 可见goodfriend函数连private类型的属性都能够访问,因为加了如下代码使全局函数变成了友元函数:

	//让全局函数:好朋友函数  变成友元函数
	friend void goodfriend(Building* building);

2. 整个类作友元类

所谓的让整个类作为友元类,意思是让某个类成为另一个类的friend类

#include<iostream>
#include<string>
using namespace std;

//要在前面先加上这行代码,防止在goodfriend类中声明Building属性时报错
class Building;


class goodfriend {
public:
	goodfriend();
	void visit();
private:
	Building* building;
};

class Building {

public:
	string m_room;    //客厅

	Building()
	{
		this->m_Bedroom = "卧室";
		this->m_room = "客厅";
	}

private:
	string m_Bedroom; //卧室
};

goodfriend::goodfriend()
{
	building = new Building;
}

void goodfriend::visit()
{
	cout << "好朋友正在访问" << this->building->m_room << endl;
	cout << "好朋友正在访问" << this->building->m_Bedroom << endl;
}

void test()
{
	goodfriend gf;
	gf.visit();
}

int main()
{
	test();
}

此时会报错,因为goodfriend类还不是building类的友元类

加上以下添加友元类的代码即可:

	//让googfreind类作为Building类的友元类,语法如下:
	friend class goodfriend;

完整代码:

#include<iostream>
#include<string>
using namespace std;

//要在前面先加上这行代码,防止在goodfriend类中声明Building属性时报错
class Building;

class goodfriend {
public:
	goodfriend();
	void visit();
private:
	Building* building;
};

class Building {

	//让googfreind类作为Building类的友元类,语法如下:
	friend class goodfriend;

public:
	string m_room;    //客厅

	Building()
	{
		this->m_Bedroom = "卧室";
		this->m_room = "客厅";
	}

private:
	string m_Bedroom; //卧室
};

goodfriend::goodfriend()
{
	building = new Building;
}

void goodfriend::visit()
{
	cout << "好朋友正在访问" << this->building->m_room << endl;
	cout << "好朋友正在访问" << this->building->m_Bedroom << endl;
}

void test()
{
	goodfriend gf;
	gf.visit();
}

int main()
{
	test();
}

 

    [友元类注意]

  1. 友元关系不能被继承
  2. 友元关系是单向的,类A是类B的朋友,但类B不一定是类A的朋友
  3. 友元关系不具有传递性。类B是类A的朋友,类C是类B的朋友,但类C不一定是类A的朋友

3.成员函数作友元函数

        将成员函数定义为友元函数时一定要注意加上函数的定义域!

#include<iostream>
#include<string>
using namespace std;

class Building;
class goodfriend {
public:
	goodfriend();
	void visit();
private:
	Building* building;
};

class Building {

	//将visit函数定义为Building类的友元函数,一定注意前面加函数的定义域goodfriend()
	friend void goodfriend::visit();

public:
	string m_room;    //客厅

	Building()
	{
		this->m_Bedroom = "卧室";
		this->m_room = "客厅";
	}

private:
	string m_Bedroom; //卧室
};

goodfriend::goodfriend()
{
	building = new Building;
}

void goodfriend::visit()
{
	cout << "好朋友正在访问" << this->building->m_room << endl;
	cout << "好朋友正在访问" << this->building->m_Bedroom << endl;
}


void test()
{
	goodfriend gf;
	gf.visit();
}

int main()
{
	test();
}

运行结果:

 

相关文章:

  • 【C++】类和对象(四)“这三种”成员变量只能放在初始化列表中初始化,你都知道吗?
  • dubbo 报错
  • 物联网入门
  • 企业实施ERP系统遇到的问题及应对措施
  • matlab | 函数:常用函数
  • 多云容器集群服务的设计与实现
  • 博睿数据携手亚马逊云科技,助您开启全链路可观测之旅
  • 面试算法 二叉树的遍历,方法递归,前序遍历: 中序遍历: 后序遍历: 层序遍历
  • 5.无霍尔BLDC转子预定位及同步加速
  • dubbo 大数据量传输 报错 ,调节默认8M调节成80M解决方案
  • 混合使用设计模式:策略模式+工厂模式+模板方法模式
  • Python对象循环引用垃圾回收算法
  • 基于Web的盾构机盾尾变形远程监测系统
  • Docker网络代理设置
  • 《大数据之路:阿里巴巴大数据实践》-第1篇 数据技术篇 -第4章 离线数据开发
  • [PHP内核探索]PHP中的哈希表
  • Google 是如何开发 Web 框架的
  • Effective Java 笔记(一)
  • Java知识点总结(JDBC-连接步骤及CRUD)
  • Lucene解析 - 基本概念
  • Objective-C 中关联引用的概念
  • passportjs 源码分析
  • react-core-image-upload 一款轻量级图片上传裁剪插件
  • SegmentFault 社区上线小程序开发频道,助力小程序开发者生态
  • spring-boot List转Page
  • Sublime text 3 3103 注册码
  • 关于使用markdown的方法(引自CSDN教程)
  • 记一次用 NodeJs 实现模拟登录的思路
  • 理清楚Vue的结构
  • 前端
  • 如何用Ubuntu和Xen来设置Kubernetes?
  • 什么是Javascript函数节流?
  • 在Mac OS X上安装 Ruby运行环境
  • 栈实现走出迷宫(C++)
  • 7行Python代码的人脸识别
  • ​一、什么是射频识别?二、射频识别系统组成及工作原理三、射频识别系统分类四、RFID与物联网​
  • # 执行时间 统计mysql_一文说尽 MySQL 优化原理
  • $HTTP_POST_VARS['']和$_POST['']的区别
  • ()、[]、{}、(())、[[]]命令替换
  • (1) caustics\
  • (1)(1.13) SiK无线电高级配置(五)
  • (12)目标检测_SSD基于pytorch搭建代码
  • (C#)if (this == null)?你在逗我,this 怎么可能为 null!用 IL 编译和反编译看穿一切
  • (HAL)STM32F103C6T8——软件模拟I2C驱动0.96寸OLED屏幕
  • (带教程)商业版SEO关键词按天计费系统:关键词排名优化、代理服务、手机自适应及搭建教程
  • (附源码)计算机毕业设计SSM智能化管理的仓库管理
  • (四)c52学习之旅-流水LED灯
  • (一)u-boot-nand.bin的下载
  • **Java有哪些悲观锁的实现_乐观锁、悲观锁、Redis分布式锁和Zookeeper分布式锁的实现以及流程原理...
  • .NET 6 Mysql Canal (CDC 增量同步,捕获变更数据) 案例版
  • .net 7 上传文件踩坑
  • .NET Framework 和 .NET Core 在默认情况下垃圾回收(GC)机制的不同(局部变量部分)
  • .Net 高效开发之不可错过的实用工具
  • .net 前台table如何加一列下拉框_如何用Word编辑参考文献
  • .net连接MySQL的方法